<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Annie’s Substack]]></title><description><![CDATA[My personal Substack]]></description><link>https://artofmaking.substack.com</link><image><url>https://substackcdn.com/image/fetch/$s_!BhPU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F384e7f1e-e08b-4113-a6c2-86f9a98f4fe5_144x144.png</url><title>Annie’s Substack</title><link>https://artofmaking.substack.com</link></image><generator>Substack</generator><lastBuildDate>Thu, 09 Apr 2026 01:52:50 GMT</lastBuildDate><atom:link href="https://artofmaking.substack.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Annie Drake]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[artofmaking@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[artofmaking@substack.com]]></itunes:email><itunes:name><![CDATA[Annie Drake]]></itunes:name></itunes:owner><itunes:author><![CDATA[Annie Drake]]></itunes:author><googleplay:owner><![CDATA[artofmaking@substack.com]]></googleplay:owner><googleplay:email><![CDATA[artofmaking@substack.com]]></googleplay:email><googleplay:author><![CDATA[Annie Drake]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Motion Warping]]></title><description><![CDATA[Setup Notes]]></description><link>https://artofmaking.substack.com/p/motion-warping</link><guid isPermaLink="false">https://artofmaking.substack.com/p/motion-warping</guid><dc:creator><![CDATA[Annie Drake]]></dc:creator><pubDate>Tue, 04 Feb 2025 23:07:02 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!WEkU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba14e0d1-1188-44c1-bc48-974da16ac7bf_917x562.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>What is it: </p><p>Updates an animation so it contorts gracefully when asked to move or rotate a distance</p><p></p><p>Enable Motion Warping in your plugins</p><p>In your animation sequence, check EnableRootMotion</p><p>In your animation montage (if you don&#8217;t have one, right click the Animation Sequence &gt; Create &gt; Create AnimMontage)  right click in notifies track, Add Notify State &gt; Motion Warping</p><ul><li><p>Set the bounds around the area movement is occurring most</p></li><li><p>Under Details </p><ul><li><p>Anim Notify &gt; Root Motion Modifier: Select Adjustment Blend Warp</p></li><li><p>Give it a Sync Point Name</p></li><li><p>Warp Translation toggles whether the warping will impact the character position</p></li><li><p>Ignore ZAxis will toggle whether or not the character is locked to the ground</p></li><li><p>Warp Rotation will toggle whether the character will rotate to face target</p><ul><li><p>Default: Instancing the rotation of the object in the world</p></li><li><p>Facing: Will face the direction of the object.</p></li></ul></li></ul></li></ul><p>In the Character&#8217;s Blueprint:</p><ul><li><p>Add a component called &#8220;Motion Warping&#8221;</p></li><li><p>Drag this into your event graph, and connect it to &#8220;Add or Update Warp Target from location and rotation&#8221;</p><ul><li><p>Set the warp target name to match the Sync Point name in your Animation Montage</p></li><li><p>Target location and rotation are where the object will target</p></li></ul></li><li><p>Get the actor you want to target</p><ul><li><p>Node &#8220;Get Actor of Class&#8221; &gt; &#8220;GetActorLocation&#8221;</p></li><li><p>plug into either translation, rotation, or both, depending on effect you want</p></li></ul></li><li><p>Play Anim Montage</p><ul><li><p>Drag the mesh in, &#8220;Play Montage&#8221;&#8217;</p></li><li><p>Select montage asset</p></li></ul></li></ul><p>In Animation Blueprint</p><ul><li><p>if you don&#8217;t already have it, create Montage &gt; &#8220;Slot&#8217;DefaultSlot&#8217;&#8221; and feed that into Output Pose</p><ul><li><p>Which slot you play in is determined in your Animation Montage</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!M0e1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff70bfabd-5d51-487b-94aa-23d38d349749_1531x296.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!M0e1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff70bfabd-5d51-487b-94aa-23d38d349749_1531x296.png 424w, https://substackcdn.com/image/fetch/$s_!M0e1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff70bfabd-5d51-487b-94aa-23d38d349749_1531x296.png 848w, https://substackcdn.com/image/fetch/$s_!M0e1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff70bfabd-5d51-487b-94aa-23d38d349749_1531x296.png 1272w, https://substackcdn.com/image/fetch/$s_!M0e1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff70bfabd-5d51-487b-94aa-23d38d349749_1531x296.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!M0e1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff70bfabd-5d51-487b-94aa-23d38d349749_1531x296.png" width="1456" height="281" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f70bfabd-5d51-487b-94aa-23d38d349749_1531x296.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:281,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:128437,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!M0e1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff70bfabd-5d51-487b-94aa-23d38d349749_1531x296.png 424w, https://substackcdn.com/image/fetch/$s_!M0e1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff70bfabd-5d51-487b-94aa-23d38d349749_1531x296.png 848w, https://substackcdn.com/image/fetch/$s_!M0e1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff70bfabd-5d51-487b-94aa-23d38d349749_1531x296.png 1272w, https://substackcdn.com/image/fetch/$s_!M0e1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff70bfabd-5d51-487b-94aa-23d38d349749_1531x296.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>If you need to change the slot:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!WEkU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba14e0d1-1188-44c1-bc48-974da16ac7bf_917x562.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!WEkU!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba14e0d1-1188-44c1-bc48-974da16ac7bf_917x562.png 424w, https://substackcdn.com/image/fetch/$s_!WEkU!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba14e0d1-1188-44c1-bc48-974da16ac7bf_917x562.png 848w, https://substackcdn.com/image/fetch/$s_!WEkU!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba14e0d1-1188-44c1-bc48-974da16ac7bf_917x562.png 1272w, https://substackcdn.com/image/fetch/$s_!WEkU!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba14e0d1-1188-44c1-bc48-974da16ac7bf_917x562.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!WEkU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba14e0d1-1188-44c1-bc48-974da16ac7bf_917x562.png" width="386" height="236.567066521265" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ba14e0d1-1188-44c1-bc48-974da16ac7bf_917x562.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:562,&quot;width&quot;:917,&quot;resizeWidth&quot;:386,&quot;bytes&quot;:267046,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!WEkU!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba14e0d1-1188-44c1-bc48-974da16ac7bf_917x562.png 424w, https://substackcdn.com/image/fetch/$s_!WEkU!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba14e0d1-1188-44c1-bc48-974da16ac7bf_917x562.png 848w, https://substackcdn.com/image/fetch/$s_!WEkU!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba14e0d1-1188-44c1-bc48-974da16ac7bf_917x562.png 1272w, https://substackcdn.com/image/fetch/$s_!WEkU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba14e0d1-1188-44c1-bc48-974da16ac7bf_917x562.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p></p></li></ul></li></ul><p></p><p></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[PyQt Basics]]></title><description><![CDATA[Basic window layout]]></description><link>https://artofmaking.substack.com/p/pyqt-basics</link><guid isPermaLink="false">https://artofmaking.substack.com/p/pyqt-basics</guid><dc:creator><![CDATA[Annie Drake]]></dc:creator><pubDate>Thu, 04 Jul 2024 15:45:52 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!BhPU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F384e7f1e-e08b-4113-a6c2-86f9a98f4fe5_144x144.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I just wanted a frame for building basic interfaces in Maya, so jumping into PyQt</p><pre><code><code>import pymel.core as pm
from PySide2 import QtWidgets, QtCore
import maya.OpenMayaUI as omui
from shiboken2 import wrapInstance

def maya_main_window():
    main_window_ptr = omui.MQtUtil.mainWindow()
    return wrapInstance(int(main_window_ptr), QtWidgets.QWidget)

class BasicWindow(QtWidgets.QDialog):
    def __init__(self, parent=maya_main_window()):
        super(BasicWindow,self).__init__(parent)
        self.setWindowTitle("My Basic Window")
        self.setMinimumWidth(200)
        
        self.setWindowFlags(self.windowFlags() ^ QtCore.Qt.WindowContextHelpButtonHint)
        
        self.create_widgets()
        self.create_layouts()
        self.create_connections()

    def create_widgets(self):
        #add widgets here later
        pass

    def create_layouts(self):
        #add layout here later
        main_layout = QtWidgets.QVBoxLayout(self)

    def create_connections(self):
        #connect signals and slots here
        pass

def show():
    ui=BasicWindow()
    ui.show()

show()</code></code></pre><p>Breakdown:</p><ul><li><p>Import the necessary modules</p><ul><li><p>import pymel.core as pm</p><ul><li><p>This line gives us access to Maya&#8217;s functionality</p><ul><li><p>Python module that gives an object oriented programming approach to Maya&#8217;s MEL language</p></li></ul></li></ul></li><li><p>from PySide2 import QtWidgets.QtCore</p><ul><li><p>This line creates our GUI system and handles the elements</p><ul><li><p>The Qt Framework is a comprehensive set of C++ library classes</p></li><li><p>PySide2 is Qt for Python</p></li><li><p>QtWidgets contains classes for creating classic desktop-style UIs</p></li><li><p>QtCore provides non-UI functionality, like signal and slot mechanisms, property systems, ect</p></li></ul></li></ul></li><li><p>import maya.OpenMayaUI as omui</p><ul><li><p>This gives us a reference to maya&#8217;s main window</p><ul><li><p>OpenMaya is Maya&#8217;s API, and openMayaUI provides access to Maya&#8217;s UI system</p></li></ul></li></ul></li><li><p>from shiboken2 import wrapInstance</p><ul><li><p>This is used to wrap Maya&#8217;s main window pointer into a PySide2 widget object</p><ul><li><p>Shiboken2 is a binding generator tool used by PySide2</p></li><li><p>WrapInstance is used to convert C++ pointers to Python objects</p></li></ul></li></ul></li></ul></li><li><p>Define maya_main_window() function to create a parent for our dialog</p><ul><li><p>This creates an interface which is parented to Maya&#8217;s UI interface, ensuring that it is part of the program and abides by its rule set.</p></li><li><p>As it will be part of the interface, maya will handle things for us like object stacking, keyboard focus and input events are handled properly, lifecycle dialog (it will close when maya closes)</p></li><li><p>It is also using a wrap instance, to convert this pointer to a PySide2 Widget, giving us that library of UI functionality</p></li></ul></li><li><p>Creates a BasicWindow class that inherits from QtWidgets.QDialog</p><ul><li><p>Because BasicWindowe is inheriting from QtWidgets.QDiagog, it has the Qt C++ library functionality</p><ul><li><p>Qt comes with built in functionality like standard button layouts and default closing behaviors</p></li></ul></li><li><p>Our __init__(parent) window links us to Maya&#8217;s main window</p></li></ul></li><li><p>Defines basic window properties</p><ul><li><p>Basic things like title name and width</p></li></ul></li><li><p>Defines placeholder methods for creating widgets, layouts and connections</p><ul><li><p>create_widgets():</p><ul><li><p>Individual UI elements that are interactive, such as buttons, text fields, drop down menus, checkboxes, sliders, ect</p></li><li><p>Examples UI elements you can use</p><ul><li><p>QPushButton</p></li><li><p>QLineEdit</p></li><li><p>QComboBox</p></li><li><p>QCheckBox</p></li><li><p>QSlider</p></li></ul></li></ul></li><li><p>create_layouts():</p><ul><li><p>Manage the layout and organizaton of widgets (how are they positioned, how do they resize, ect)</p></li><li><p>Common layouts are things like horizontal, vertial, grid and form</p></li><li><p>Example Layouts:</p><ul><li><p>QVBoxLayout</p></li><li><p>QHBoxLayout</p></li><li><p>QGridLayout</p></li><li><p>QFormLayout</p></li></ul></li></ul></li><li><p>create_connections()</p><ul><li><p>Connections take user interactions with your widgets and link them to code behavior</p></li><li><p>This is where you setup signal slot connections, which is how Qt handles events</p></li><li><p>Like in other programming environments, a signal is what is sent out when a UI event is triggered (like a button click) and and slots are the functions which respond to those events</p></li><li><p>This is where you would connect widget signals to slots</p></li></ul></li></ul></li><li><p>Provides a &#8220;show()&#8221; function to add and display the window</p><p></p></li></ul><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;8d0df0ec-b8ee-460b-8b3a-b026ac0d1ea2&quot;,&quot;duration&quot;:null}"></div><p>Here is a practical application of that script, which overrides the selected NURBS shape&#8217;s color override with a set color (the words in bold are what we added to modify the last script for our purposes):  </p><pre><code>import pymel.core as pm
from PySide2 import QtWidgets, QtCore
import maya.OpenMayaUI as omui
from shiboken2 import wrapInstance

def maya_main_window():
    main_window_ptr = omui.MQtUtil.mainWindow()
    return wrapInstance(int(main_window_ptr), QtWidgets.QWidget)
    
class <strong>CurveColorUI</strong>(QtWidgets.QDialog):
    def __init__(self, parent=maya_main_window()):
        super(CurveColorUI,self).__init__(parent)
        
        self.setWindowTitle("<strong>Set Curve Color</strong>")
        self.setMinimumWidth(200)
        
        self.setWindowFlags(self.windowFlags() ^ QtCore.Qt.WindowContextHelpButtonHint)  

        <em><strong>#replace the "self.setWindowFlags" with the below code in italixBold to get rid of the help toggle (it is not setup to do anything)</strong>
        <strong>#flags = self.windowFlags()
        #flags &amp;= ~QtCore.Qt.WindowContextHelpButtonHint
        #self.setWindowFlags(flags)</strong></em>
        
        self.create_widgets()
        self.create_layouts()
        self.create_connections()
        
    def create_widgets(self):
        <strong>self.color_combo = QtWidgets.QComboBox()
        self.color_combo.addItems
        (["Red","Green","Blue","Yellow","Cyan","Magenta"])</strong>
        
        <strong>self.apply_btn = QtWidgets.QPushButton("Apply")</strong>
        
    def create_layouts(self):
        main_layout = QtWidgets.QVBoxLayout(self)
        <strong>main_layout.addWidget(self.color_combo)
        main_layout.addWidget(self.apply_btn)</strong>
        
    def create_connections(self):
        <strong>self.apply_btn.clicked.connect(self.apply_color)</strong>
        
    <strong>def apply_color(self):
        color_name = self.color_combo.currentText()
        color_index = {"Red":13, "Green":14, "Blue":15, "Yellow":17, "Cyan":18, "Magenta":20}[color_name]
        
        selected_curves = pm.ls(selection = True, type = 'transform')
        for curve in selected_curves:
            shapes = curve.getShapes()
            for shape in shapes:
                if isinstance(shape, pm.nodetypes.NurbsCurve):
                    shape.overrideEnabled.set(1)
                    shape.overrideRGBColors.set(0)
                    shape.overrideColor.set(color_index)
                    
        pm.select(selected_curves) #reselect the curves</strong>
        
def show():
    ui=<strong>CurveColorUI</strong>()
    ui.show()
        
show()</code></pre>]]></content:encoded></item><item><title><![CDATA[Expression Editor Math Functions]]></title><description><![CDATA[Personal Notes]]></description><link>https://artofmaking.substack.com/p/expression-editor-math-functions</link><guid isPermaLink="false">https://artofmaking.substack.com/p/expression-editor-math-functions</guid><dc:creator><![CDATA[Annie Drake]]></dc:creator><pubDate>Tue, 02 Jul 2024 11:18:12 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!BhPU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F384e7f1e-e08b-4113-a6c2-86f9a98f4fe5_144x144.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Taking notes on the math functions available in the expression editor, because the <a href="https://maya-math-nodes.readthedocs.io/en/latest/node_reference.html#node-reference">documentation</a> uses circular descriptions.</p><p><strong>Absolute</strong> </p><ul><li><p>The value (decimal or whole) of a number converted into the positive axis.</p></li><li><p>Example: The absolute value of -5 is 5, of 5 is 5, of 1.2 is 1.2, of -1.2 is 1.2</p></li><li><p>Useful in rigging scenarios where you need to work with the magnitude regardless of direction or sign.  Its particularly useful with symmetry and distance based effects.</p></li></ul><p><strong>Acos</strong></p><ul><li><p>This is helpful in rigging scenarios that involve angle calculations, especially with normalized vectors.  Its commonly used in orientation constraints, calculating joint angles, and solving various geometric problems in 3D space, in combination with other trigonometric and vector operations. </p></li><li><p>Takes a value between -1 and 1, and returns an angle (in radians) whose cosine is the input value</p></li><li><p>Example: </p><ul><li><p>float $value = 0.5;</p><p>float $angle = acos($value);</p><p>// $angle will be approximately 1.0472 radians (60 degrees)</p></li></ul></li><li><p>This is used in rigging to:</p><ul><li><p>Calculate angles between vectors</p></li><li><p>Creating arc based motions</p></li><li><p>Inverse trigonometric relationships</p></li></ul></li><li><p>Practical - calculate the angle between two objects and stores it in a control attribute</p><ul><li><p>vector $vector1 = &lt;&lt;object1.translateX, object1.translateY, object1.translateZ&gt;&gt;;</p><p>vector $vector2 = &lt;&lt;object2.translateX, object2.translateY, object2.translateZ&gt;&gt;;</p><p>vector $normalized1 = normalize($vector1);</p><p>vector $normalized2 = normalize($vector2);</p><p>float $dotProduct = dot($normalized1, $normalized2);</p><p>float $angle = acos($dotProduct);</p><p>// Convert to degrees for easier interpretation</p><p>control.angle = rad_to_deg($angle);</p></li></ul></li><li><p>Notes:</p><ul><li><p>The output is in radians, so convert to degrees if needed</p></li><li><p>Acos is often used in conjunction with dot product for angle calculations</p></li></ul></li></ul><p><strong>Add</strong></p><ul><li><p>Adds two values together</p></li><li><p>Example</p><ul><li><p>float $value1 = 5;</p><p>float $value2 = 3;</p><p>float $result = $value1 + $value2;  // result is 8</p></li></ul></li></ul><p><strong>AndBool</strong></p><ul><li><p>One of the logical operators, useful to ensure multiple criteria are met before triggering an action</p></li><li><p>There are two variants:</p><ul><li><p>AndBool (for boolean values)</p></li><li><p>AndInt (for integer values, treating non-zero as true)</p></li></ul></li><li><p>Syntax: &amp;&amp;</p></li><li><p>Example:</p><ul><li><p>int $condition1 = control1.attribute &gt; 0;</p><p>int $condition2 = control2.attribute &lt; 10;</p><p>int $result = $condition1 &amp;&amp; $condition2;</p></li></ul></li></ul><p><strong>AngleBetweenVectors</strong></p><ul><li><p>Excellent for creating orientation aware behaviors in rigging.  Its useful in scenarios involving aiming, constraint systems, or any situation where you need to understand or manipulate the relationship between directions in 3D space.  </p></li><li><p>Syntax: anglebetween(vector1, vector2)</p></li><li><p>Functionality:</p><ul><li><p>Takes two vectors as input</p></li><li><p>returns the angle between those vectors in radians</p></li></ul></li><li><p>Example:</p><ul><li><p>vector $vec1 = &lt;&lt;1, 0, 0&gt;&gt;;</p><p>vector $vec2 = &lt;&lt;0, 1, 0&gt;&gt;;</p><p>float $angle = anglebetween($vec1, $vec2);</p><p>// $angle will be approximately 1.5708 radians (90 degrees)</p></li></ul></li><li><p>Usages:</p><ul><li><p>Calculating joint angles</p></li><li><p>Creating orientation based constraints</p></li><li><p>Implementing aim or lookat behaviors</p></li><li><p>Designating rotation limits or angle based effects</p></li></ul></li><li><p>Practical - a simple aim constraint that rotates an object to point at its target</p><ul><li><p>vector $objectPos = &lt;&lt;object.translateX, object.translateY, object.translateZ&gt;&gt;;</p><p>vector $targetPos = &lt;&lt;target.translateX, target.translateY, target.translateZ&gt;&gt;;</p><p>vector $upVector = &lt;&lt;0, 1, 0&gt;&gt;;  // World up vector</p><p>vector $aimVector = normalize($targetPos - $objectPos);</p><p>vector $rightVector = normalize(cross($upVector, $aimVector));</p><p>vector $newUpVector = cross($aimVector, $rightVector);</p><p>float $yRotation = anglebetween(&lt;&lt;1, 0, 0&gt;&gt;, &lt;&lt;$aimVector.x, 0, $aimVector.z&gt;&gt;);</p><p>float $xRotation = anglebetween($aimVector, $newUpVector) - 90;</p><p>if ($aimVector.z &lt; 0) $yRotation = -$yRotation;</p><p>object.rotateY = rad_to_deg($yRotation);</p><p>object.rotateX = rad_to_deg($xRotation);</p></li></ul></li><li><p>Advanced Practical - Creating a join rotation limit system</p><ul><li><p>vector $parentForward = &lt;&lt;1, 0, 0&gt;&gt;;  // Assuming local X is forward</p><p>vector $childPosition = &lt;&lt;child.translateX, child.translateY, child.translateZ&gt;&gt;;</p><p>float $angle = anglebetween($parentForward, $childPosition);</p><p>float $maxAngle = deg_to_rad(45);  // 45 degree limit</p><p>if ($angle &gt; $maxAngle) {</p><p>    vector $limitedVector = normalize($childPosition) * sin($maxAngle);</p><p>    child.translateX = $limitedVector.x;</p><p>    child.translateY = $limitedVector.y;</p><p>    child.translateZ = $limitedVector.z;</p><p>}</p></li></ul></li></ul><p><strong>Asin</strong></p><ul><li><p>Asin calculates the inverse sine (aka the arc sine) of a given value.  It&#8217;s useful in rigging scenarios that involve calculating angles from normalized values or component ratios.  Its used in creating arc-based motions, solving inverse kinematic problems, and any situation where you need to determine angle based on a sine value.  Typically used concurrently with other trigonometric and vector operations.</p></li><li><p>Syntax: asin(value)</p></li><li><p>Functionality:</p><ul><li><p>Takes a value between -1 and 1 as input</p></li><li><p>Returns the angle (in radians) whose sine is the input value</p></li><li><p>Output range is -90&#176; to 90&#176;</p></li></ul></li><li><p>Example:</p><ul><li><p>float $value = 0.5;</p><p>float $angle = asin($value);</p><p>// $angle will be approximately 0.5236 radians (30 degrees)</p></li></ul></li><li><p>Practical - a rig that calculates the elevation angle of a object from the XZ plane and stores it in a control attribute</p><ul><li><p>vector $objectPos = &lt;&lt;object.translateX, object.translateY, object.translateZ&gt;&gt;;</p><p>vector $planeNormal = &lt;&lt;0, 1, 0&gt;&gt;; // Assuming XZ plane</p><p>vector $direction = normalize($objectPos);</p><p>float $dotProduct = dot($direction, $planeNormal);</p><p>float $elevationAngle = asin($dotProduct);</p><p>// Convert to degrees for easier interpretation</p><p>control.elevationAngle = rad_to_deg($elevationAngle);</p></li></ul></li><li><p>Advanced Practical - create a semicircular motion path based on the input attribute</p><ul><li><p>float $input = control.inputAttr;  // Assume this ranges from -1 to 1</p><p>float $angle = asin($input);</p><p>float $radius = 5;</p><p>float $x = $radius * $input;</p><p>float $y = $radius * cos($angle);</p><p>object.translateX = $x;</p><p>object.translateY = $y;</p></li></ul></li></ul><p><strong>Atan</strong></p><ul><li><p>Calculates the Arc Tangent function - it&#8217;s useful in rigging scenarios that involve calculating angles based on ratios or in situations where you need to determine orientation from positional data.  Its often used in look at systems, dynamic rotation calculations, and in creating responsive rig elements that need to orient themselves based on spatial relationships.</p></li><li><p>Syntax: atan(value)</p></li><li><p>Functionality:</p><ul><li><p>Takes any real number as an input</p></li><li><p>Returns the angle (in radians)</p></li><li><p>Output range is -90&#176; to 90&#176;</p></li></ul></li><li><p>Example: </p><ul><li><p>float $value = 1;</p><p>float $angle = atan($value);</p><p>// $angle will be approximately 0.7854 radians (45 degrees)</p></li></ul></li><li><p>Practical - create a simple look at behavior for an object</p><ul><li><p>vector $objectPos = &lt;&lt;object.translateX, object.translateY, object.translateZ&gt;&gt;;</p><p>vector $targetPos = &lt;&lt;target.translateX, target.translateY, target.translateZ&gt;&gt;;</p><p>vector $direction = $targetPos - $objectPos;</p><p>float $yRotation = atan($direction.x / $direction.z);</p><p>float $xRotation = atan($direction.y / sqrt($direction.x * $direction.x + $direction.z * $direction.z));</p><p>// Adjust for quadrant</p><p>if ($direction.z &lt; 0) $yRotation += 3.14159;</p><p>object.rotateY = rad_to_deg($yRotation);</p><p>object.rotateX = rad_to_deg($xRotation);</p></li></ul></li><li><p>Advanced Practical - using for dynamic foot placement, this adjusts the foot&#8217;s rotation to match an angled floor surface.</p><ul><li><p>float $floorHeight = 0;</p><p>float $toePos = toe.translateY;</p><p>float $heelPos = heel.translateY;</p><p>float $footLength = abs(toe.translateZ - heel.translateZ);</p><p>float $floorAngle = atan(($toePos - $heelPos) / $footLength);</p><p>foot.rotateX = rad_to_deg($floorAngle);</p></li></ul></li></ul><p><strong>Atan2</strong> </p><ul><li><p>Calculates the inverse tangent of y/x, taking into account the quadrant of the resulting angle.  It is a more advanced system than the arc tangent, it&#8217;s valuable in scenarios where you need to calculate angles that cover all 360&#176;, such as look-at systems, circular motions, or when dealing with local coordinate systems.</p></li><li><p>Syntax: atan(y,x)</p></li><li><p>Functionality</p><ul><li><p>Takes two inputs, y and x (in that order)</p></li><li><p>Returns the angle (in radians) from positive x-axis to the point (x, y)</p></li><li><p>Output range is (-180&#176; to 180&#176;)</p></li></ul></li><li><p>Example:</p><ul><li><p>float $y = 1;</p><p>float $x = -1;</p><p>float $angle = atan($y, $x);</p><p>// $angle will be approximately 2.3562 radians (135 degrees)</p></li></ul></li><li><p>Practical - an improved lookat behavior that handles all quadrants correctly, allowing the system to rotate a full 180&#176;</p><ul><li><p>vector $objectPos = &lt;&lt;object.translateX, object.translateY, object.translateZ&gt;&gt;;</p><p>vector $targetPos = &lt;&lt;target.translateX, target.translateY, target.translateZ&gt;&gt;;</p><p>vector $direction = $targetPos - $objectPos;</p><p>float $yRotation = atan($direction.x, $direction.z);</p><p>float $xRotation = atan($direction.y, sqrt($direction.x * $direction.x + $direction.z * $direction.z));</p><p>object.rotateY = rad_to_deg($yRotation);</p><p>object.rotateX = -rad_to_deg($xRotation);  // Negative because Maya's rotation is opposite</p></li></ul></li><li><p>Advanced Practical - adjusts a foot&#8217;s rotation to match uneven terrain, considering both pitch and roll</p><ul><li><p>vector $anklePos = &lt;&lt;ankle.translateX, ankle.translateY, ankle.translateZ&gt;&gt;;</p><p>vector $toePos = &lt;&lt;toe.translateX, toe.translateY, toe.translateZ&gt;&gt;;</p><p>vector $heelPos = &lt;&lt;heel.translateX, heel.translateY, heel.translateZ&gt;&gt;;</p><p>vector $footForward = $toePos - $heelPos;</p><p>vector $footUp = cross($footForward, &lt;&lt;1, 0, 0&gt;&gt;);</p><p>float $slopeAngle = atan($footUp.y, $footUp.z);</p><p>foot.rotateX = rad_to_deg($slopeAngle);</p></li></ul></li></ul><p><strong>Average</strong></p><ul><li><p>Calculates the arithmetic mean of a set of values</p></li><li><p>Variants:</p><ul><li><p>Average (float)</p></li><li><p>AverageInt (int)</p></li><li><p>AverageAngle (angle)</p></li><li><p>AverageVector (vector)</p></li><li><p>AverageMatrix (matrix)</p></li></ul></li><li><p>Syntax: average([value1,value2,value3,&#8230;])g</p></li><li><p>Example: </p><ul><li><p>float $values[] = {10, 20, 30, 40, 50};</p><p>float $result = average($values);</p><p>// $result will be 30</p></li></ul></li><li><p>Practical - a control which centers itself at the average location of multiple objects:</p><ul><li><p>vector $positions[];</p><p>$positions[0] = &lt;&lt;object1.translateX, object1.translateY, object1.translateZ&gt;&gt;;</p><p>$positions[1] = &lt;&lt;object2.translateX, object2.translateY, object2.translateZ&gt;&gt;;</p><p>$positions[2] = &lt;&lt;object3.translateX, object3.translateY, object3.translateZ&gt;&gt;;</p><p>vector $averagePos = average($positions);</p><p>control.translateX = $averagePos.x;</p><p>control.translateY = $averagePos.y;</p><p>control.translateZ = $averagePos.z;</p></li></ul></li><li><p>Advanced Practical - Creates a camera that smoothly follows a target by averaging its positions over several frames</p><ul><li><p>vector $targetPositions[];</p><p>int $numFrames = 10;</p><p>for ($i = 0; $i &lt; $numFrames; $i++) {</p><p>    float $time = `currentTime -q` - $i;</p><p>    setAttr time1.outTime $time;</p><p>    $targetPositions[$i] = &lt;&lt;target.translateX, target.translateY, target.translateZ&gt;&gt;;</p><p>}</p><p>vector $averagePos = average($targetPositions);</p><p>camera.translateX = $averagePos.x;</p><p>camera.translateY = $averagePos.y;</p><p>camera.translateZ = $averagePos.z;</p></li></ul></li></ul><p><strong>AxisFromMatrix</strong></p><ul><li><p>Extracts a specific axis vector from a transformation matrix.  You can use it to extract local or world space orientations, create aim up or vector constraints, implement space switching mechanisms, and analyze object orientations in complex hierarchies.</p></li><li><p>Syntax: axis(matrix,axis) //matrix is the input matrix and axis is an integer</p></li><li><p>Functionality</p><ul><li><p>Takes a transformation matrix and an axis index as input</p></li><li><p>Returns a vector representing the axis from the matrix</p></li><li><p>Returns a normalized vector (unit length)</p></li></ul></li><li><p>Example:</p><ul><li><p>vector $matrix[4] = `object.worldMatrix`;</p><p>int $axisIndex = 0;  // 0 for X-axis</p><p>vector $axisVector = axis($matrix, $axisIndex);</p></li></ul></li><li><p>Practical - Simple aim constraint using the forward axis of an object:</p><ul><li><p>vector $sourceMatrix[4] = `source.worldMatrix`;</p><p>vector $forwardAxis = axis($sourceMatrix, 0);  // Assuming X is forward</p><p>vector $targetPos = &lt;&lt;target.translateX, target.translateY, target.translateZ&gt;&gt;;</p><p>vector $sourcePos = &lt;&lt;source.translateX, source.translateY, source.translateZ&gt;&gt;;</p><p>vector $toTarget = normalize($targetPos - $sourcePos);</p><p>float $dotProduct = dot($forwardAxis, $toTarget);</p><p>vector $crossProduct = cross($forwardAxis, $toTarget);</p><p>float $angle = acos($dotProduct);</p><p>vector $rotationAxis = normalize($crossProduct);</p><p>// Convert to degrees and apply rotation</p><p>float $rotationAngle = rad_to_deg($angle);</p><p>setAttr("source.rotateX", $rotationAxis.x * $rotationAngle);</p><p>setAttr("source.rotateY", $rotationAxis.y * $rotationAngle);</p><p>setAttr("source.rotateZ", $rotationAxis.z * $rotationAngle);</p></li></ul></li><li><p>Advanced Practical - Calculates a twist angle for an object based on its local up vector compared to the worlds up</p><ul><li><p>vector $objectMatrix[4] = `object.worldMatrix`;</p><p>vector $upVector = axis($objectMatrix, 1);  // Y-axis as up</p><p>vector $forwardVector = axis($objectMatrix, 0);  // X-axis as forward</p><p>vector $worldUp = &lt;&lt;0, 1, 0&gt;&gt;;</p><p>vector $rightVector = normalize(cross($forwardVector, $worldUp));</p><p>vector $newUpVector = normalize(cross($rightVector, $forwardVector));</p><p>float $upDot = dot($upVector, $newUpVector);</p><p>vector $upCross = cross($upVector, $newUpVector);</p><p>float $twistAngle = atan2(dot($upCross, $forwardVector), $upDot);</p><p>object.twist = rad_to_deg($twistAngle);</p></li></ul></li></ul><p><strong>Ceil</strong></p><ul><li><p>Rounds a floating point number up to the nearest integer.</p></li><li><p>Types:</p><ul><li><p>Ceil (floats)</p></li><li><p>CeilAngle (for angles)</p></li></ul></li><li><p>Syntax: ceil(value)</p></li><li><p>Example:</p><ul><li><p>float $value1 = 3.2;</p><p>float $value2 = 3.8;</p><p>float $result1 = ceil($value1);  // result1 will be 4</p><p>float $result2 = ceil($value2);  // result2 will be 4</p></li></ul></li><li><p>Practical - Snaps an object to the nearest integer grid point above its current position in all axes</p><ul><li><p>float $rawX = control.translateX;</p><p>float $rawY = control.translateY;</p><p>float $rawZ = control.translateZ;</p><p>float $snappedX = ceil($rawX);</p><p>float $snappedY = ceil($rawY);</p><p>float $snappedZ = ceil($rawZ);</p><p>object.translateX = $snappedX;</p><p>object.translateY = $snappedY;</p><p>object.translateZ = $snappedZ;</p></li></ul></li></ul><p><strong>Clamp</strong></p><ul><li><p>Restricts a value to stay within a specific range.</p></li><li><p>Variants:</p><ul><li><p>Clamp (float)</p></li><li><p>ClampInt (int)</p></li><li><p>ClampAngle (angle)</p></li></ul></li><li><p>Syntax: clamp(value, min, max)</p></li><li><p>Functionality:</p><ul><li><p>Takes three inputs, the value to be clamped, the minimum allowed value, and the maximum allowed value.</p></li><li><p>Returns the input if its with range</p></li><li><p>Returns the max if its above the max, or the min if its below the min range.</p></li></ul></li><li><p>Example: </p><ul><li><p>float $value = 15;</p><p>float $min = 0;</p><p>float $max = 10;</p><p>float $result = clamp($value, $min, $max);</p><p>// $result will be 10</p></li></ul></li><li><p>Practical - Create a control that limites an object&#8217;s scale between 0.5 and 2</p><ul><li><p>float $scaleX = object.scaleX;</p><p>float $scaleY = object.scaleY;</p><p>float $scaleZ = object.scaleZ;</p><p>float $minScale = 0.5;</p><p>float $maxScale = 2.0;</p><p>object.scaleX = clamp($scaleX, $minScale, $maxScale);</p><p>object.scaleY = clamp($scaleY, $minScale, $maxScale);</p><p>object.scaleZ = clamp($scaleZ, $minScale, $maxScale);</p></li></ul></li><li><p>Advanced Practical - creating a smooth falloff effect</p><ul><li><p>vector $objectPos = &lt;&lt;object.translateX, object.translateY, object.translateZ&gt;&gt;;</p><p>vector $centerPos = &lt;&lt;center.translateX, center.translateY, center.translateZ&gt;&gt;;</p><p>float $distance = mag($objectPos - $centerPos);</p><p>float $maxDistance = 10;</p><p>float $minDistance = 2;</p><p>float $falloff = 1 - clamp(($distance - $minDistance) / ($maxDistance - $minDistance), 0, 1);</p><p>object.scaleX = lerp(0.5, 1, $falloff);</p><p>object.scaleY = lerp(0.5, 1, $falloff);</p><p>object.scaleZ = lerp(0.5, 1, $falloff);</p></li></ul></li></ul><p><strong>Compare</strong></p><ul><li><p>Evaluates the relationship between two values and returns an int indicating their relative order.</p></li><li><p>Variants:</p><ul><li><p>Compare (float)</p></li><li><p>CompareInt (int)</p></li><li><p>CompareAngle (angle)</p></li></ul></li><li><p>Syntax: compare(value1, value2)</p></li><li><p>Functionality:</p><ul><li><p>Takes 2 values as an input</p></li><li><p>Returns -1 if value1 is less than value2</p></li><li><p>Returns 0 if value 1 is equal to value2</p></li><li><p>Returns 1 if value1 is greater than value2</p></li></ul></li><li><p>Example:</p><ul><li><p>float $value1 = 5;</p><p>float $value2 = 10;</p><p>int $result = compare($value1, $value2);</p><p>// $result will be -1</p></li></ul></li><li><p>Practical - simple state machine based on an object&#8217;s position:</p><ul><li><p>float $posX = object.translateX;</p><p>int $state = compare($posX, 0);</p><p>if ($state == -1) {</p><p>    setAttr("leftLight.intensity", 1);</p><p>    setAttr("rightLight.intensity", 0);</p><p>} else if ($state == 1) {</p><p>    setAttr("leftLight.intensity", 0);</p><p>    setAttr("rightLight.intensity", 1);</p><p>} else {</p><p>    setAttr("leftLight.intensity", 0.5);</p><p>    setAttr("rightLight.intensity", 0.5);</p><p>}</p></li></ul></li><li><p>Practical Advanced - a dynamic parenting system</p><ul><li><p>float $controlValue = control.parentingAttr;</p><p>vector $targets[] = {&lt;&lt;target1.translateX, target1.translateY, target1.translateZ&gt;&gt;,</p><p>                     &lt;&lt;target2.translateX, target2.translateY, target2.translateZ&gt;&gt;,</p><p>                     &lt;&lt;target3.translateX, target3.translateY, target3.translateZ&gt;&gt;};</p><p>int $index = 0;</p><p>for ($i = 1; $i &lt; size($targets); $i++) {</p><p>    if (compare($controlValue, $i) &lt; 0) {</p><p>        break;</p><p>    }</p><p>    $index = $i;</p><p>}</p><p>vector $parentPos = $targets[$index];</p><p>object.translateX = $parentPos.x;</p><p>object.translateY = $parentPos.y;</p><p>object.translateZ = $parentPos.z;</p></li></ul></li></ul><p><strong>CosAngle</strong></p><ul><li><p>CosAngle calculates the cosine of an input angle.   Its useful in generating wave-like behaviors, circular motions, and in solving trigonometric problems.</p></li><li><p>Syntax: cos(angle)</p></li><li><p>Functionality:</p><ul><li><p>Takes an angle as input (in radians)</p></li><li><p>Returns the cosine of that angle (a value between -1 and 1)</p></li><li><p>Works with floats</p></li></ul></li><li><p>Example:</p><ul><li><p>float $angleInDegrees = 60;</p><p>float $angleInRadians = deg_to_rad($angleInDegrees);</p><p>float $result = cos($angleInRadians);</p><p>// $result will be approximately 0.5</p></li></ul></li><li><p>Practical - creating a simple oscillating side-to-side motion:</p><ul><li><p>float $time = `currentTime -q`;</p><p>float $frequency = 0.1;  // Controls how fast the oscillation occurs</p><p>float $amplitude = 5;    // Controls the range of the motion</p><p>float $xPosition = $amplitude * cos($time * $frequency);</p><p>object.translateX = $xPosition;</p></li></ul></li><li><p>Advanced Practical - Creates a look-at behavior with an additional twist calculation using cosine</p><ul><li><p>vector $targetPos = &lt;&lt;target.translateX, target.translateY, target.translateZ&gt;&gt;;</p><p>vector $objectPos = &lt;&lt;object.translateX, object.translateY, object.translateZ&gt;&gt;;</p><p>vector $direction = normalize($targetPos - $objectPos);</p><p>float $yRotation = atan2($direction.x, $direction.z);</p><p>float $xRotation = asin(-$direction.y);</p><p>object.rotateY = rad_to_deg($yRotation);</p><p>object.rotateX = rad_to_deg($xRotation);</p><p>// Calculate twist</p><p>float $upDotX = dot(&lt;&lt;0,1,0&gt;&gt;, &lt;&lt;cos($yRotation), 0, -sin($yRotation)&gt;&gt;);</p><p>float $twist = acos($upDotX);</p><p>object.rotateZ = rad_to_deg($twist);</p></li></ul></li></ul><p><strong>CrossProduct</strong></p><ul><li><p>Calculates the vector perpendicular to two input vectors.  This is helpful in creating orientation matrices, calculating surface normals, and implementing various constraints.</p></li><li><p>Syntax: cross(vector1, vector2)</p></li><li><p>Functionality:</p><ul><li><p>Takes two Vector3 values as input</p></li><li><p>Returns a new vector perpendicular to both input vectors</p></li><li><p>Resulting vector follows right hand rule</p></li></ul></li><li><p>Example:</p><ul><li><p> vector $vec1 = &lt;&lt;1, 0, 0&gt;&gt;;  // X-axis</p><p>vector $vec2 = &lt;&lt;0, 1, 0&gt;&gt;;  // Y-axis</p><p>vector $result = cross($vec1, $vec2);</p><p>// $result will be &lt;&lt;0, 0, 1&gt;&gt; (Z-axis)</p></li></ul></li><li><p>Practical - a simple aim constraint with an automatic up-vector:</p><ul><li><p>vector $objectPos = &lt;&lt;object.translateX, object.translateY, object.translateZ&gt;&gt;;</p><p>vector $targetPos = &lt;&lt;target.translateX, target.translateY, target.translateZ&gt;&gt;;</p><p>vector $aimVector = normalize($targetPos - $objectPos);</p><p>vector $worldUp = &lt;&lt;0, 1, 0&gt;&gt;;</p><p>vector $rightVector = normalize(cross($aimVector, $worldUp));</p><p>vector $upVector = normalize(cross($rightVector, $aimVector));</p><p>float $aimMatrix[4][4] = </p><p>    $aimVector.x, $aimVector.y, $aimVector.z, 0,</p><p>    $upVector.x, $upVector.y, $upVector.z, 0,</p><p>    $rightVector.x, $rightVector.y, $rightVector.z, 0,</p><p>    $objectPos.x, $objectPos.y, $objectPos.z, 1</p><p>&gt;&gt;;</p><p>setAttr object.matrix $aimMatrix;</p></li></ul></li><li><p>Advanced Practical - creating a ribbon-like deformation between two joints with a sinusoidal twist</p><ul><li><p>vector $startPos = &lt;&lt;startJoint.translateX, startJoint.translateY, startJoint.translateZ&gt;&gt;;</p><p>vector $endPos = &lt;&lt;endJoint.translateX, endJoint.translateY, endJoint.translateZ&gt;&gt;;</p><p>vector $upVector = &lt;&lt;0, 1, 0&gt;&gt;;</p><p>vector $ribbonDir = normalize($endPos - $startPos);</p><p>vector $ribbonWidth = normalize(cross($ribbonDir, $upVector));</p><p>float $ribbonLength = mag($endPos - $startPos);</p><p>float $currentU = uCoordinate;  // Assume we have a U coordinate from 0 to 1</p><p>vector $ribbonPoint = $startPos + $ribbonDir * ($currentU * $ribbonLength);</p><p>vector $offset = $ribbonWidth * sin($currentU * 2 * 3.14159) * 2;</p><p>point.translateX = $ribbonPoint.x + $offset.x;</p><p>point.translateY = $ribbonPoint.y + $offset.y;</p><p>point.translateZ = $ribbonPoint.z + $offset.z;</p></li></ul></li></ul><p><strong>DebugLog</strong></p><ul><li><p>Prints a value to the Maya Script Editor</p></li><li><p>Variants:</p><ul><li><p>DebugLog (float)</p></li><li><p>DebugLogInt (int)</p></li><li><p>DebugLogVector (vector)</p></li><li><p>DebugLogAngle (angles)</p></li><li><p>DebugLogMatrix (matrix)</p></li></ul></li><li><p>Syntax: debuglog(value)</p></li><li><p>Example:</p><ul><li><p>float $value = 3.14;</p><p>float $result = debuglog($value);</p><p>// Prints "3.14" to the Script Editor</p><p>// $result will be 3.14</p></li></ul></li><li><p>Practical - monitor a simple IK stretching setup</p><ul><li><p>vector $startPos = &lt;&lt;startJoint.translateX, startJoint.translateY, startJoint.translateZ&gt;&gt;;</p><p>vector $endPos = &lt;&lt;endJoint.translateX, endJoint.translateY, endJoint.translateZ&gt;&gt;;</p><p>float $currentLength = mag(debuglog($endPos - $startPos));</p><p>float $originalLength = 10;  // Assume this is the original chain length</p><p>float $stretchFactor = debuglog($currentLength / $originalLength);</p><p>middleJoint.scaleX = $stretchFactor;</p></li></ul></li></ul><p><strong>Divide</strong></p><ul><li><p>Classic division</p></li><li><p>Variants</p><ul><li><p>Divide (float)</p></li><li><p>DivideAngle (angle)</p></li><li><p>DivideByInt (divides a float by an integer)</p></li><li><p>DivideAngleByInt (divides an angle by an integer)</p></li></ul></li><li><p>Syntax: x / y</p></li><li><p>Example:</p><ul><li><p>float $value1 = 10;</p><p>float $value2 = 2;</p><p>float $result = $value1 / $value2;</p><p>// $result will be 5</p></li></ul></li><li><p>Practical - a simple stretch IK system</p><ul><li><p>vector $startPos = &lt;&lt;startJoint.translateX, startJoint.translateY, startJoint.translateZ&gt;&gt;;</p><p>vector $endPos = &lt;&lt;endJoint.translateX, endJoint.translateY, endJoint.translateZ&gt;&gt;;</p><p>float $currentLength = mag($endPos - $startPos);</p><p>float $originalLength = 10;  // Assume this is the original chain length</p><p>float $stretchFactor = $currentLength / $originalLength;</p><p>if ($stretchFactor &gt; 1) {</p><p>    middleJoint.scaleX = $stretchFactor;</p><p>} else {</p><p>    middleJoint.scaleX = 1;</p><p>}</p></li></ul></li></ul><p><strong>DotProduct</strong></p><ul><li><p>DotProduct calculates the scalar product of two vectors.  It is useful for calculating angles, determining alignment, and creating direction-based effects.</p></li><li><p>Syntax: dot(vector1, vector2)</p></li><li><p>Example:</p><ul><li><p>vector $vec1 = &lt;&lt;1, 0, 0&gt;&gt;;</p><p>vector $vec2 = &lt;&lt;0, 1, 0&gt;&gt;;</p><p>float $result = dot($vec1, $vec2);</p><p>// $result will be 0 (because the vectors are perpendicular)</p></li></ul></li><li><p>Practical - create a simple look-at behavior with a falloff effect, this scales an object based on how well its aligned with its target:</p><ul><li><p>vector $objectPos = &lt;&lt;object.translateX, object.translateY, object.translateZ&gt;&gt;;</p><p>vector $targetPos = &lt;&lt;target.translateX, target.translateY, target.translateZ&gt;&gt;;</p><p>vector $toTarget = normalize($targetPos - $objectPos);</p><p>vector $objectForward = &lt;&lt;object.worldMatrix[0].x, object.worldMatrix[0].y, object.worldMatrix[0].z&gt;&gt;;</p><p>float $alignment = dot($toTarget, $objectForward);</p><p>// $alignment will be 1 when perfectly aligned, -1 when opposite, and 0 when perpendicular</p><p>float $falloff = ($alignment + 1) / 2;  // Remap to 0-1 range</p><p>object.scaleX = lerp(0.5, 1, $falloff);</p><p>object.scaleY = lerp(0.5, 1, $falloff);</p><p>object.scaleZ = lerp(0.5, 1, $falloff);</p></li></ul></li><li><p>Advanced Practical - create a surface sliding behavior, where an object slides along as urface, removing any movement in the direction of the surface normal</p><ul><li><p>vector $objectPos = &lt;&lt;object.translateX, object.translateY, object.translateZ&gt;&gt;;</p><p>vector $surfaceNormal = &lt;&lt;surface.normalX, surface.normalY, surface.normalZ&gt;&gt;;</p><p>vector $moveVector = &lt;&lt;control.translateX, control.translateY, control.translateZ&gt;&gt;;</p><p>float $normalComponent = dot($moveVector, $surfaceNormal);</p><p>vector $tangentVector = $moveVector - $surfaceNormal * $normalComponent;</p><p>object.translateX = $objectPos.x + $tangentVector.x;</p><p>object.translateY = $objectPos.y + $tangentVector.y;</p><p>object.translateZ = $objectPos.z + $tangentVector.z;</p></li></ul></li></ul><p><strong>DistancePoints</strong></p><ul><li><p>Calculates the Euclidean distance between two points in 3D space.  Useful for creating distance-based behaviors, implementing stretch systems, and designing proximity-based effects.  Other usages might be calculating lengths of joints or limbs, implementing distance based constraints, or creating falloffs based on proximity, or measuring spatial relationships between objects.</p></li><li><p>Variants:</p><ul><li><p>DistancePoints (for point to point distance)</p></li><li><p>DistanceTransforms (for distance between transform nodes)</p></li></ul></li><li><p>Syntax: distance(point1,point2)</p></li><li><p>Functionality:</p><ul><li><p>Takes two Vector3s as input</p></li><li><p>Returns a scalar value representing the strait line distance between the points</p></li></ul></li><li><p>Example: </p><ul><li><p>vector $point1 = &lt;&lt;0, 0, 0&gt;&gt;;</p><p>vector $point2 = &lt;&lt;3, 4, 0&gt;&gt;;</p><p>float $result = distance($point1, $point2);</p><p>// $result will be 5</p></li></ul></li><li><p>Practical - a simple stretchy IK setup, in which the arm scales uniformly when extended beyond its original length</p><ul><li><p>vector $shoulderPos = &lt;&lt;shoulder.translateX, shoulder.translateY, shoulder.translateZ&gt;&gt;;</p><p>vector $handPos = &lt;&lt;hand.translateX, hand.translateY, hand.translateZ&gt;&gt;;</p><p>float $currentLength = distance($shoulderPos, $handPos);</p><p>float $originalLength = 10;  // Assume this is the original arm length</p><p>float $stretchFactor = $currentLength / $originalLength;</p><p>upperArm.scaleX = $stretchFactor;</p><p>lowerArm.scaleX = $stretchFactor;</p></li></ul></li><li><p> Advanced Practical - Creating a proximity based blending system, where an object is influenced by multiple targets based on proximity</p><ul><li><p>vector $objectPos = &lt;&lt;object.translateX, object.translateY, object.translateZ&gt;&gt;;</p><p>vector $influences[];</p><p>float $weights[];</p><p>float $maxDistance = 10;</p><p>for ($i = 1; $i &lt;= 3; $i++) {</p><p>    $influences[$i] = &lt;&lt;(`target$i.translateX`), (`target$i.translateY`), (`target$i.translateZ`)&gt;&gt;;</p><p>    float $dist = distance($objectPos, $influences[$i]);</p><p>    $weights[$i] = 1 - clamp($dist / $maxDistance, 0, 1);</p><p>}</p><p>float $totalWeight = $weights[1] + $weights[2] + $weights[3];</p><p>if ($totalWeight &gt; 0) {</p><p>    vector $blendedPosition = &lt;&lt;0, 0, 0&gt;&gt;;</p><p>    for ($i = 1; $i &lt;= 3; $i++) {</p><p>        $blendedPosition += $influences[$i] * ($weights[$i] / $totalWeight);</p><p>    }</p><p>    object.translateX = $blendedPosition.x;</p><p>    object.translateY = $blendedPosition.y;</p><p>    object.translateZ = $blendedPosition.z;</p><p>}</p></li></ul></li></ul><p><strong>Floor</strong></p><ul><li><p>Floor rounds a floating point number down to the nearest integer</p></li><li><p>Variants:</p><ul><li><p>Floor (float)</p></li><li><p>FloorAngle (angle)</p></li></ul></li><li><p>Syntax: floor(value)</p></li><li><p>Example: </p><ul><li><p>float $value1 = 3.7;</p><p>float $value2 = -2.1;</p><p>float $result1 = floor($value1);  // result1 will be 3</p><p>float $result2 = floor($value2);  // result2 will be -3</p></li></ul></li><li><p>Practical - creates a stepped rotation system, which controls that step in 45&#176; increments, always rounding down</p><ul><li><p>float $rotationStep = 45;  // Rotate in 45-degree increments</p><p>float $currentRotation = control.rotateY;</p><p>float $steppedRotation = floor($currentRotation / $rotationStep) * $rotationStep;</p><p>object.rotateY = $steppedRotation;</p></li></ul></li></ul><p><strong>Inverse</strong></p><ul><li><p>Calculates the inverse of a given value or transformation.  Useful for handling transformations and space conversions, like complex hierarchical relationships or space switching systems.  It provides a way to invert values and transformations, allowing riggers to create more flexible control systems, and enabling objects to maintain their positions and orientations across different coordinate spaces.</p></li><li><p>Variants:</p><ul><li><p>Inverse (float)</p></li><li><p>InverseMatrix (for matricies)</p></li><li><p>InverseQuaternion (for quaternions)</p></li><li><p>InverseRotation (for rotations)</p></li></ul></li><li><p>Syntax: inverse(value)</p></li><li><p>Functionality: </p><ul><li><p>For scalars: Returns 1 divided by the input</p></li><li><p>For matrices:  Returns the inverse matrix</p></li><li><p>For quaternions and rotations: returns the inverse rotation</p></li></ul></li><li><p>Example: </p><ul><li><p>float $scalar = 2;</p><p>float $inverseScalar = inverse($scalar);  // Result: 0.5</p><p>vector $matrix[4] = `object.worldMatrix`;</p><p>vector $inverseMatrix[4] = inverse($matrix);</p></li></ul></li><li><p>Practical - a simple space switching system, which converts an object&#8217;s world space to local space relative to the parent object</p><ul><li><p>vector $worldMatrix[4] = `object.worldMatrix`;</p><p>vector $parentMatrix[4] = `parent.worldMatrix`;</p><p>vector $localMatrix[4] = inverse($parentMatrix) * $worldMatrix;</p><p>setAttr object.matrix $localMatrix;</p></li></ul></li><li><p>Practical Advanced - Creates a dynamic parent constraint, which creates a smooth transition between world space and parent space for a child object</p><ul><li><p>vector $childWorldMatrix[4] = `child.worldMatrix`;</p><p>vector $parentWorldMatrix[4] = `parent.worldMatrix`;</p><p>float $parentInfluence = parent.influence;  // Assume this ranges from 0 to 1</p><p>if ($parentInfluence &gt; 0) {</p><p>    vector $parentLocalMatrix[4] = inverse($parentWorldMatrix) * $childWorldMatrix;</p><p>    vector $blendedLocalMatrix[4] = slerp(`child.matrix`, $parentLocalMatrix, $parentInfluence);</p><p>    vector $newWorldMatrix[4] = $parentWorldMatrix * $blendedLocalMatrix;</p><p>    setAttr child.matrix $newWorldMatrix;</p><p>}</p></li></ul></li></ul><p><strong>Lerp</strong></p><ul><li><p>Lerp takes the input of one value, and then drives the output between two other given values.  This is a classic way to create smooth transitions, and is particularly helpful when you need to interpolate between known states or values.</p></li><li><p>Variants:</p><ul><li><p>Lerp (float)</p></li><li><p>LerpAngle (angle)</p></li><li><p>LerpVector (vector)</p></li><li><p>LerpMatrix (matrix)</p></li></ul></li><li><p>Syntax: lerp(value1,value2,alpha)</p></li><li><p>Functionality</p><ul><li><p>Takes three inputs, two values to interpolate between, and an alpha (how much they should blend between each other)</p></li><li><p>Returns a value linearly interpolated between value1 and value2</p></li><li><p>Alpha typically ranges between 0 (full value1) and 1 (full value2)</p></li></ul></li><li><p>Example:</p><ul><li><p>float $value1 = 0;</p><p>float $value2 = 10;</p><p>float $alpha = 0.3;</p><p>float $result = lerp($value1, $value2, $alpha);</p><p>// $result will be 3</p></li></ul></li><li><p>Practical - a simple blend between two rotations, controlled by a single attribute</p><ul><li><p>vector $rotation1 = &lt;&lt;0, 0, 0&gt;&gt;;</p><p>vector $rotation2 = &lt;&lt;90, 45, 30&gt;&gt;;</p><p>float $blendFactor = control.blendAttr;  // Assume this ranges from 0 to 1</p><p>vector $blendedRotation = lerp($rotation1, $rotation2, $blendFactor);</p><p>object.rotateX = $blendedRotation.x;</p><p>object.rotateY = $blendedRotation.y;</p><p>object.rotateZ = $blendedRotation.z;</p></li></ul></li><li><p>Advanced Practical - a multi-target blending system where an object can be blended between three different positions</p><ul><li><p>vector $pos1 = &lt;&lt;target1.translateX, target1.translateY, target1.translateZ&gt;&gt;;</p><p>vector $pos2 = &lt;&lt;target2.translateX, target2.translateY, target2.translateZ&gt;&gt;;</p><p>vector $pos3 = &lt;&lt;target3.translateX, target3.translateY, target3.translateZ&gt;&gt;;</p><p>float $blend1 = control.blend1;</p><p>float $blend2 = control.blend2;</p><p>vector $intermediatPos = lerp($pos1, $pos2, $blend1);</p><p>vector $finalPos = lerp($intermediatPos, $pos3, $blend2);</p><p>object.translateX = $finalPos.x;</p><p>object.translateY = $finalPos.y;</p><p>object.translateZ = $finalPos.z;</p></li></ul></li></ul><p><strong>MatrixFrom</strong></p><ul><li><p>Used to create a transformation matrix from various input components.  This is useful in rigging for creating complex transformations, setting up space switching, or defining custom object orientations.</p></li><li><p>Syntax:</p><ul><li><p>matrixFromRotation(rotateX, rotateY, rotateZ, rotationOrder)</p></li><li><p>matrixFrom(scale, rotation, translation)</p></li><li><p>matrixFromTranslation(translateX, translateY, translateZ)</p></li><li><p>matrixFromDirection(directionVector, upVector)</p></li><li><p>matrixFromElements(XX, XY, XZ, XW, YX, YY, YZ, YW, ZX, ZY, ZZ, ZW, WX, WY, WZ, WW)</p></li></ul></li><li><p>Functionality: </p><ul><li><p>Inputs: depends on which variant you are targeting</p></li><li><p>Output: a 4x4 transformation matrix</p></li></ul></li><li><p>Example:</p><ul><li><p>// Create a rotation matrix and apply it to an object</p><p>matrix $rotMatrix = matrixFromRotation(object1.rotateX, object1.rotateY, object1.rotateZ, "xyz");</p><p>object2.matrix = $rotMatrix;</p></li></ul></li><li><p>Practical - Space Switching for IK Controls</p><ul><li><p>// Switch between local and world space for an IK control</p><p>matrix $localMatrix = matrixFrom(&lt;&lt;1,1,1&gt;&gt;, &lt;&lt;ikControl.rotateX, ikControl.rotateY, ikControl.rotateZ&gt;&gt;, &lt;&lt;ikControl.translateX, ikControl.translateY, ikControl.translateZ&gt;&gt;);</p><p>matrix $parentMatrix = parent.worldMatrix;</p><p>matrix $worldMatrix = $localMatrix * $parentMatrix;</p><p>if (ikControl.space == 0) // Local space</p><p>    ikHandle.matrix = $localMatrix;</p><p>else // World space</p><p>    ikHandle.matrix = $worldMatrix;</p></li></ul></li><li><p>Advanced Practical - Ribbon Spine System</p><ul><li><p>// Create a ribbon-like spine system</p><p>vector $startPos = &lt;&lt;startJoint.translateX, startJoint.translateY, startJoint.translateZ&gt;&gt;;</p><p>vector $endPos = &lt;&lt;endJoint.translateX, endJoint.translateY, endJoint.translateZ&gt;&gt;;</p><p>vector $spineVector = unit($endPos - $startPos);</p><p>vector $upVector = &lt;&lt;0, 1, 0&gt;&gt;;</p><p>vector $sideVector = unit(cross($spineVector, $upVector));</p><p>matrix $spineMatrix = matrixFromDirection($spineVector, $upVector);</p><p>// Apply to middle joint</p><p>middleJoint.matrix = $spineMatrix;</p></li></ul></li></ul><p><strong>MatrixFromDirection</strong></p><ul><li><p>Creates a rotation matrix that orients an object to face a specified direction.  Useful when you need objects to face or align with specific directions while maintaining a stable up orientation.  It simplifies the process of creating look at behaviors, aim constrains, and other direction-based orientation systems.</p></li><li><p>Syntax: direction(directionVector, upVector)</p></li><li><p>Functionality:</p><ul><li><p>Takes two inputs, a direction vector and up vector</p></li><li><p>Returns a 4x4 matrix representing the rotation that aligns an object&#8217;s local forward axis with the direction vector.</p></li><li><p>Uses the up vector to determine the object&#8217;s local up direction.</p></li></ul></li><li><p>Example: </p><ul><li><p>vector $directionVec = &lt;&lt;1, 1, 1&gt;&gt;;</p><p>vector $upVec = &lt;&lt;0, 1, 0&gt;&gt;;</p><p>vector $resultMatrix[4] = direction($directionVec, $upVec);</p></li></ul></li><li><p>Practical - orients an object to always face a target object</p><ul><li><p>vector $objectPos = &lt;&lt;object.translateX, object.translateY, object.translateZ&gt;&gt;;</p><p>vector $targetPos = &lt;&lt;target.translateX, target.translateY, target.translateZ&gt;&gt;;</p><p>vector $directionVec = normalize($targetPos - $objectPos);</p><p>vector $upVec = &lt;&lt;0, 1, 0&gt;&gt;;  // World up vector</p><p>vector $lookAtMatrix[4] = direction($directionVec, $upVec);</p><p>// Extract rotation from matrix</p><p>vector $rotation = rot($lookAtMatrix, "xyz");</p><p>object.rotateX = rad_to_deg($rotation.x);</p><p>object.rotateY = rad_to_deg($rotation.y);</p><p>object.rotateZ = rad_to_deg($rotation.z);</p></li></ul></li><li><p>Advanced Practical - creating a ribbon-like chain of objects</p><ul><li><p>int $numObjects = 10;</p><p>vector $startPos = &lt;&lt;startObj.translateX, startObj.translateY, startObj.translateZ&gt;&gt;;</p><p>vector $endPos = &lt;&lt;endObj.translateX, endObj.translateY, endObj.translateZ&gt;&gt;;</p><p>vector $chainDir = normalize($endPos - $startPos);</p><p>vector $upVec = &lt;&lt;0, 1, 0&gt;&gt;;</p><p>vector $sideVec = normalize(cross($chainDir, $upVec));</p><p>$upVec = cross($sideVec, $chainDir);</p><p>for ($i = 0; $i &lt; $numObjects; $i++) {</p><p>    float $t = (float)$i / ($numObjects - 1);</p><p>    vector $pos = $startPos + $chainDir * ($t * mag($endPos - $startPos));</p><p>    vector $localUp = $upVec * sin($t * 2 * 3.14159) + $sideVec * cos($t * 2 * 3.14159);</p><p>    vector $orientMatrix[4] = direction($chainDir, $localUp);</p><p>    setAttr ("object" + ($i+1) + ".translateX") $pos.x;</p><p>    setAttr ("object" + ($i+1) + ".translateY") $pos.y;</p><p>    setAttr ("object" + ($i+1) + ".translateZ") $pos.z;</p><p>    setAttr ("object" + ($i+1) + ".matrix") $orientMatrix;</p><p>}</p></li></ul></li></ul><p><strong>MatrixfromTRS</strong></p><ul><li><p>Constructs a 4x4 transformation matrix from separate translation, rotation and scale components.  It allows you to combine all these values into a single matrix, which is crucial for complex transformation operations, space switching, and advanced constraint systems.</p></li><li><p>Syntax: trs(translation, rotation, scale)</p></li><li><p>Functionality:</p><ul><li><p>Takes three inputs, a translation vector, a rotation (euler or quaternion) and a scale vector</p></li><li><p>Returns a 4x4 matrix that represents the combined transformation</p></li><li><p>Applies the transformations in the order, scale, then rotate, then translate</p></li></ul></li><li><p>Example:</p><ul><li><p>vector $translation = &lt;&lt;10, 20, 30&gt;&gt;;</p><p>vector $rotation = &lt;&lt;0, 90, 0&gt;&gt;;  // In degrees</p><p>vector $scale = &lt;&lt;2, 2, 2&gt;&gt;;</p><p>vector $resultMatrix[4] = trs($translation, deg_to_rad($rotation), $scale);</p></li></ul></li><li><p>Practical - a simple space switching setup between local and parent space</p><ul><li><p>vector $localTranslate = &lt;&lt;object.translateX, object.translateY, object.translateZ&gt;&gt;;</p><p>vector $localRotate = &lt;&lt;deg_to_rad(object.rotateX), </p><p>                        deg_to_rad(object.rotateY), </p><p>                        deg_to_rad(object.rotateZ)&gt;&gt;;</p><p>vector $localScale = &lt;&lt;object.scaleX, object.scaleY, object.scaleZ&gt;&gt;;</p><p>vector $localMatrix[4] = trs($localTranslate, $localRotate, $localScale);</p><p>int $spaceSwitch = control.spaceSwitch;  // 0 for world, 1 for parent</p><p>vector $parentMatrix[4] = `parent.worldMatrix`;</p><p>if ($spaceSwitch == 1) {</p><p>    vector $worldMatrix[4] = $parentMatrix * $localMatrix;</p><p>    setAttr object.matrix $worldMatrix;</p><p>} else {</p><p>    setAttr object.matrix $localMatrix;</p><p>}</p></li></ul></li><li><p>Advanced Practical - an animated transformation combining oscillating translation, rotation, and scaling</p><ul><li><p>float $time = `currentTime -q`;</p><p>vector $translation = &lt;&lt;sin($time * 0.1) * 10, cos($time * 0.2) * 5, 0&gt;&gt;;</p><p>vector $rotation = &lt;&lt;0, $time * 10, 0&gt;&gt;;  // Rotate around Y-axis</p><p>vector $scale = &lt;&lt;1 + sin($time * 0.05) * 0.2, </p><p>                 1 + sin($time * 0.05) * 0.2, </p><p>                 1 + sin($time * 0.05) * 0.2&gt;&gt;;</p><p>vector $animMatrix[4] = trs($translation, deg_to_rad($rotation), $scale);</p><p>setAttr object.matrix $animMatrix;</p></li></ul></li></ul><p><strong>Max</strong></p><ul><li><p>Returns the larger of two variables</p></li><li><p>Variants:</p><ul><li><p>Max (float)</p></li><li><p>MaxInt (Int)</p></li><li><p>MaxAngle (Angle)</p></li></ul></li><li><p>Syntax: max(value1, value2)</p></li><li><p>Functionality:</p><ul><li><p>Takes two input values</p></li><li><p>Returns the larger of the two inputs</p></li></ul></li><li><p>Example: </p><ul><li><p>float $value1 = 5.3;</p><p>float $value2 = 7.8;</p><p>float $result = max($value1, $value2);</p><p>// $result will be 7.8</p></li></ul></li><li><p>Practical - Creating a stretchy IK Limb with a minimum length:</p><ul><li><p>def stretchy_ik(start_joint, end_joint, ik_handle, min_length):</p><p>    current_length = distance(start_joint.worldMatrix[3], end_joint.worldMatrix[3])</p><p>    original_length = ik_handle.poleVectorX  # Assuming we stored the original length here</p><p>    stretch_factor = max(current_length / original_length, 1)</p><p>    start_joint.scaleX = stretch_factor</p><p>    start_joint.scaleY = max(1 / sqrt(stretch_factor), min_length / original_length)</p><p>    start_joint.scaleZ = max(1 / sqrt(stretch_factor), min_length / original_length)</p></li><li><p>in this example the limb never compresses below its original length and maintains a minimum thickness.</p></li></ul></li><li><p>Advanced Practical - dynamic scaling system based on distance</p><ul><li><p>vector $objectPos = &lt;&lt;object.translateX, object.translateY, object.translateZ&gt;&gt;;</p><p>vector $targetPos = &lt;&lt;target.translateX, target.translateY, target.translateZ&gt;&gt;;</p><p>float $distance = mag($targetPos - $objectPos);</p><p>float $minScale = 0.5;</p><p>float $scaleFactorPerUnit = 0.1;</p><p>float $dynamicScale = max($minScale, 1 + $distance * $scaleFactorPerUnit);</p><p>object.scaleX = $dynamicScale;</p><p>object.scaleY = $dynamicScale;</p><p>object.scaleZ = $dynamicScale;</p></li></ul></li></ul><p><strong>MaxElement</strong></p><ul><li><p>Returns the largest value from an array of values</p></li><li><p>Variants</p><ul><li><p>MaxElement (float)</p></li><li><p>MaxIntElement (Int)</p></li><li><p>MaxAngleElement (Angle)</p></li></ul></li><li><p>Syntax: maxelement(array)</p></li><li><p>Functionality:</p><ul><li><p>Takes an array of numeric values as an input</p></li><li><p>Returns the largest value in the array</p></li></ul></li><li><p>Example:</p><ul><li><p>float $values[] = {3.5, 7.2, 1.8, 9.1, 4.6};</p><p>float $result = maxelement($values);</p><p>// $result will be 9.1</p></li></ul></li><li><p>Practical - Scales an object based on the largest scale factor from three different influences</p><ul><li><p>float $scaleFactors[];</p><p>$scaleFactors[0] = influence1.scaleFactorAttr;</p><p>$scaleFactors[1] = influence2.scaleFactorAttr;</p><p>$scaleFactors[2] = influence3.scaleFactorAttr;</p><p>float $maxScaleFactor = maxelement($scaleFactors);</p><p>object.scaleX = $maxScaleFactor;</p><p>object.scaleY = $maxScaleFactor;</p><p>object.scaleZ = $maxScaleFactor;</p></li></ul></li><li><p>Advanced Practical - orients a control object based on the maximum rotation values from multiple joints</p><ul><li><p>vector $jointOrientations[];</p><p>$jointOrientations[0] = &lt;&lt;joint1.rotateX, joint1.rotateY, joint1.rotateZ&gt;&gt;;</p><p>$jointOrientations[1] = &lt;&lt;joint2.rotateX, joint2.rotateY, joint2.rotateZ&gt;&gt;;</p><p>$jointOrientations[2] = &lt;&lt;joint3.rotateX, joint3.rotateY, joint3.rotateZ&gt;&gt;;</p><p>float $maxRotationX = maxelement(&lt;&lt;$jointOrientations[0].x, $jointOrientations[1].x, $jointOrientations[2].x&gt;&gt;);</p><p>float $maxRotationY = maxelement(&lt;&lt;$jointOrientations[0].y, $jointOrientations[1].y, $jointOrientations[2].y&gt;&gt;);</p><p>float $maxRotationZ = maxelement(&lt;&lt;$jointOrientations[0].z, $jointOrientations[1].z, $jointOrientations[2].z&gt;&gt;);</p><p>control.rotateX = $maxRotationX;</p><p>control.rotateY = $maxRotationY;</p><p>control.rotateZ = $maxRotationZ;</p></li></ul></li></ul><p><strong>Min</strong></p><ul><li><p>Min returns the smaller of two values.  Its useful in scenarios where you need to ensure maximum values, implement clamping behjaviors, or create dynamic systems that respond to the samller of two values.  </p></li><li><p>Variants</p><ul><li><p>Min (float)</p></li><li><p>MinInt (int)</p></li><li><p>MinAngle (angle)</p></li></ul></li><li><p>Syntax: min(value1, value2)</p></li><li><p>Functionality:</p><ul><li><p>Takes two input values</p></li><li><p>Returns the smaller of the two inputs</p></li><li><p>Works with numeric values (floats, ints, angles)</p></li></ul></li><li><p>Example:</p><ul><li><p>float $value1 = 5.3;</p><p>float $value2 = 7.8;</p><p>float $result = min($value1, $value2);</p><p>// $result will be 5.3</p></li></ul></li><li><p>Practical - Simple clamping system for a control&#8217;s translation, never exceeding 10 in any axis:</p><ul><li><p>float $rawX = control.translateX;</p><p>float $rawY = control.translateY;</p><p>float $rawZ = control.translateZ;</p><p>float $maxValue = 10;</p><p>float $clampedX = min($rawX, $maxValue);</p><p>float $clampedY = min($rawY, $maxValue);</p><p>float $clampedZ = min($rawZ, $maxValue);</p><p>object.translateX = $clampedX;</p><p>object.translateY = $clampedY;</p><p>object.translateZ = $clampedZ;</p></li></ul></li><li><p>Advanced Practical - a dynamic scaling system based on distance from a target, within a maximum scale of 2:</p><ul><li><p>float $rawX = control.translateX;</p><p>float $rawY = control.translateY;</p><p>float $rawZ = control.translateZ;</p><p>float $maxValue = 10;</p><p>float $clampedX = min($rawX, $maxValue);</p><p>float $clampedY = min($rawY, $maxValue);</p><p>float $clampedZ = min($rawZ, $maxValue);</p><p>object.translateX = $clampedX;</p><p>object.translateY = $clampedY;</p><p>object.translateZ = $clampedZ;</p></li></ul></li></ul><p><strong>MinElement</strong></p><ul><li><p>Returns the smallest value from an array of values.  </p></li><li><p>Variants:</p><ul><li><p>MinElement (float arrays)</p></li><li><p>MinIntElement (int arrays)</p></li><li><p>MinAngleElement (angle arrays)</p></li></ul></li><li><p>Syntax: minelement(array)</p></li><li><p>Functionality:</p><ul><li><p>Takes an array of numeric values as input</p></li><li><p>Returns the smallest value in the array</p></li><li><p>Works with arrays of floats, integers or angles</p></li></ul></li><li><p>Example:</p><ul><li><p>float $values[] = {3.5, 7.2, 1.8, 9.1, 4.6};</p><p>float $result = minelement($values);</p><p>// $result will be 1.8</p></li></ul></li><li><p>Practical - A system that scales an object based on the smallest scale factor among multiple influences</p><ul><li><p>float $scaleFactors[];</p><p>$scaleFactors[0] = influence1.scaleFactorAttr;</p><p>$scaleFactors[1] = influence2.scaleFactorAttr;</p><p>$scaleFactors[2] = influence3.scaleFactorAttr;</p><p>float $minScaleFactor = minelement($scaleFactors);</p><p>object.scaleX = $minScaleFactor;</p><p>object.scaleY = $minScaleFactor;</p><p>object.scaleZ = $minScaleFactor;</p></li></ul></li><li><p>Advanced Usage - A dynamic multi-joint compression system, based on the minimum scale of multiple joints:</p><ul><li><p>vector $jointScales[];</p><p>$jointScales[0] = &lt;&lt;joint1.scaleX, joint1.scaleY, joint1.scaleZ&gt;&gt;;</p><p>$jointScales[1] = &lt;&lt;joint2.scaleX, joint2.scaleY, joint2.scaleZ&gt;&gt;;</p><p>$jointScales[2] = &lt;&lt;joint3.scaleX, joint3.scaleY, joint3.scaleZ&gt;&gt;;</p><p>float $minScaleX = minelement(&lt;&lt;$jointScales[0].x, $jointScales[1].x, $jointScales[2].x&gt;&gt;);</p><p>float $minScaleY = minelement(&lt;&lt;$jointScales[0].y, $jointScales[1].y, $jointScales[2].y&gt;&gt;);</p><p>float $minScaleZ = minelement(&lt;&lt;$jointScales[0].z, $jointScales[1].z, $jointScales[2].z&gt;&gt;);</p><p>control.compressionX = 1 - $minScaleX;</p><p>control.compressionY = 1 - $minScaleY;</p><p>control.compressionZ = 1 - $minScaleZ;</p></li></ul></li></ul><p><strong>ModulusInt</strong></p><ul><li><p>Calculates the remainder of integer divisions between two values</p></li><li><p>Syntax: x % y</p></li><li><p>Functionality:</p><ul><li><p>Takes two integer values as input: a divident and a dividor</p></li><li><p>Returns the remainder after division of the first value by the second value</p></li></ul></li><li><p>Example</p><ul><li><p>value1 = 17</p><p>value2 = 5</p><p>result = value1 % value2</p><p># result would be 2 (17 divided by 5 is 3 with remainder 2)</p></li></ul></li><li><p>Practical - cucles an object&#8217;s color between red, green and blue every 24 frames</p><ul><li><p>float $time = `currentTime -q`;</p><p>int $cycleLength = 24;  // Change color every 24 frames</p><p>int $colorIndex = (int)$time % $cycleLength;</p><p>if ($colorIndex &lt; 8) {</p><p>    object.colorR = 1; object.colorG = 0; object.colorB = 0;  // Red</p><p>} else if ($colorIndex &lt; 16) {</p><p>    object.colorR = 0; object.colorG = 1; object.colorB = 0;  // Green</p><p>} else {</p><p>    object.colorR = 0; object.colorG = 0; object.colorB = 1;  // Blue</p><p>}</p></li></ul></li><li><p>Advanced Practical - rotates multiple objects at the same speed but with evenly distributed offsets</p><ul><li><p>int $numObjects = 5;</p><p>float $rotationSpeed = 5;  // Degrees per frame</p><p>float $time = `currentTime -q`;</p><p>for ($i = 0; $i &lt; $numObjects; $i++) {</p><p>    int $offset = ($i * 360) / $numObjects;</p><p>    float $rotation = ($time * $rotationSpeed + $offset) % 360;</p><p>    setAttr ("object" + ($i+1) + ".rotateY") $rotation;</p><p>}</p></li></ul></li></ul><p><strong>Multiply</strong></p><ul><li><p>Classic multiplication between two values</p></li><li><p>Syntax: x * y</p></li><li><p>Example:</p><ul><li><p>float $value1 = 5;</p><p>float $value2 = 3;</p><p>float $result = $value1 * $value2;</p><p>// $result will be 15</p></li></ul></li><li><p>Practical - a simple scaling system based on distance:</p><ul><li><p>vector $objectPos = &lt;&lt;object.translateX, object.translateY, object.translateZ&gt;&gt;;</p><p>vector $targetPos = &lt;&lt;target.translateX, target.translateY, target.translateZ&gt;&gt;;</p><p>float $distance = mag($targetPos - $objectPos);</p><p>float $scaleFactor = 1 - ($distance / 10);  // Assume 10 is the max distance</p><p>float $baseScale = 1;</p><p>object.scaleX = $baseScale * $scaleFactor;</p><p>object.scaleY = $baseScale * $scaleFactor;</p><p>object.scaleZ = $baseScale * $scaleFactor;</p></li></ul></li></ul><p><strong>Negate</strong></p><ul><li><p>Returns the additive inverse of a value.  Particularly useful for creating symmetrical behavior, toggle systems, and reciprocal relationships between attributes or objects.  Allows riggers a more dynamic control system, especially with mirroring, balancing, or any scenario where you need to reverse the effect of a value or motion.</p></li><li><p>Variants:</p><ul><li><p>Negate (float)</p></li><li><p>NegateAngle (Angle)</p></li><li><p>NegateInt (Int)</p></li><li><p>NegateVector (Vector)</p></li></ul></li><li><p>Syntax: negate(value) or -value</p></li><li><p>Functionality:</p><ul><li><p>Takes a value as an input</p></li><li><p>Returns the negative of that value</p></li><li><p>Multiplies the input by -1</p></li></ul></li><li><p>Example:</p><ul><li><p>float $value = 5.3;</p><p>float $result = negate($value);</p><p>// $result will be -5.3</p><p>// Alternatively:</p><p>float $result2 = -$value;</p><p>// $result2 will also be -5.3</p></li></ul></li><li><p>Practical - mirrors the rotation of a source control to a target control across the YZ</p><ul><li><p>float $sourceRotateX = sourceControl.rotateX;</p><p>float $sourceRotateY = sourceControl.rotateY;</p><p>float $sourceRotateZ = sourceControl.rotateZ;</p><p>targetControl.rotateX = negate($sourceRotateX);</p><p>targetControl.rotateY = $sourceRotateY;  // Assuming Y is the up axis</p><p>targetControl.rotateZ = negate($sourceRotateZ);</p></li></ul></li><li><p>Advanced Practicle - allows toggling between moving towards or away from an object</p><ul><li><p>float $constraintToggle = control.constraintToggle;  // Assume this is 0 or 1</p><p>vector $targetPos = &lt;&lt;target.translateX, target.translateY, target.translateZ&gt;&gt;;</p><p>vector $objectPos = &lt;&lt;object.translateX, object.translateY, object.translateZ&gt;&gt;;</p><p>vector $offset = $targetPos - $objectPos;</p><p>vector $negatedOffset = negate($offset);</p><p>vector $finalOffset = $offset * $constraintToggle + $negatedOffset * (1 - $constraintToggle);</p><p>object.translateX += $finalOffset.x;</p><p>object.translateY += $finalOffset.y;</p><p>object.translateZ += $finalOffset.z;</p></li></ul></li></ul><p><strong>NormalizeVector</strong></p><ul><li><p>Returns a unit vector (a vector with a magnitude of 1) in the same direction as the input vector.  It is useful in creating aim constraints, calculating orientations, and designing systems that rely on direction information regardless of scale or distance.</p></li><li><p>Syntax: normalize(vector)</p></li><li><p>Functionality:</p><ul><li><p>Takes a vector as input</p></li><li><p>Returns a vector pointing in the same direction but with a length of 1</p></li><li><p>If the input vector is 0, returns a 0 vector</p></li></ul></li><li><p>Example:</p><ul><li><p> vector $inputVector = &lt;&lt;3, 4, 0&gt;&gt;;</p><p>vector $normalizedVector = normalize($inputVector);</p><p>// $normalizedVector will be &lt;&lt;0.6, 0.8, 0&gt;&gt;</p></li></ul></li><li><p>Practical - creates an aim constraint where the object always faces the target while maintaining a stable up oreintation</p><ul><li><p>vector $objectPos = &lt;&lt;object.translateX, object.translateY, object.translateZ&gt;&gt;;</p><p>vector $targetPos = &lt;&lt;target.translateX, target.translateY, target.translateZ&gt;&gt;;</p><p>vector $aimVector = normalize($targetPos - $objectPos);</p><p>vector $upVector = &lt;&lt;0, 1, 0&gt;&gt;;  // World up vector</p><p>vector $rightVector = normalize(cross($aimVector, $upVector));</p><p>vector $newUpVector = normalize(cross($rightVector, $aimVector));</p><p>float $aimMatrix[4][4] = </p><p>    $aimVector.x, $aimVector.y, $aimVector.z, 0,</p><p>    $newUpVector.x, $newUpVector.y, $newUpVector.z, 0,</p><p>    $rightVector.x, $rightVector.y, $rightVector.z, 0,</p><p>    $objectPos.x, $objectPos.y, $objectPos.z, 1</p><p>&gt;&gt;;</p><p>setAttr object.matrix $aimMatrix;</p></li></ul></li><li><p>Advanced Practical - creates a ribbon-like deformation between two joints</p><ul><li><p>vector $startPos = &lt;&lt;startJoint.translateX, startJoint.translateY, startJoint.translateZ&gt;&gt;;</p><p>vector $endPos = &lt;&lt;endJoint.translateX, endJoint.translateY, endJoint.translateZ&gt;&gt;;</p><p>vector $ribbonDir = normalize($endPos - $startPos);</p><p>vector $upVector = &lt;&lt;0, 1, 0&gt;&gt;;</p><p>vector $ribbonSide = normalize(cross($ribbonDir, $upVector));</p><p>float $ribbonLength = mag($endPos - $startPos);</p><p>float $currentU = uCoordinate;  // Assume we have a U coordinate from 0 to 1</p><p>float $currentV = vCoordinate;  // Assume we have a V coordinate from -0.5 to 0.5</p><p>vector $ribbonPoint = $startPos + $ribbonDir * ($currentU * $ribbonLength);</p><p>vector $offset = $ribbonSide * $currentV * $ribbonLength * 0.1;  // 10% of length for width</p><p>point.translateX = $ribbonPoint.x + $offset.x;</p><p>point.translateY = $ribbonPoint.y + $offset.y;</p><p>point.translateZ = $ribbonPoint.z + $offset.z;</p></li></ul></li></ul><p><strong>NormalizeArray</strong></p><ul><li><p>Scales an array of values so they sum to 1, while maintaining their relative proportions.   Useful in scenarios where you need to blend between multiple inputs or targets while ensuring that the total influence always remains constant.</p></li><li><p>Syntax: normalizearray(array)</p></li><li><p>Functionality: </p><ul><li><p>Takes an array of numeric values as input</p></li><li><p>Returns an array of the same length where all values sum to 1</p></li><li><p>Maintains the relative proportions of the input values</p></li><li><p>If all input values are 0, it returns an array of equal values that sum to 1.</p></li></ul></li><li><p>Example: </p><ul><li><p>float $inputArray[] = {2, 3, 5};</p><p>float $normalizedArray[] = normalizearray($inputArray);</p><p>// $normalizedArray will be approximately {0.2, 0.3, 0.5}</p></li></ul></li><li><p>Practical - creates a constant where an object is influenced by three targets with normalized weights</p><ul><li><p>vector $target1Pos = &lt;&lt;target1.translateX, target1.translateY, target1.translateZ&gt;&gt;;</p><p>vector $target2Pos = &lt;&lt;target2.translateX, target2.translateY, target2.translateZ&gt;&gt;;</p><p>vector $target3Pos = &lt;&lt;target3.translateX, target3.translateY, target3.translateZ&gt;&gt;;</p><p>float $weights[] = {control.weight1, control.weight2, control.weight3};</p><p>float $normalizedWeights[] = normalizearray($weights);</p><p>vector $blendedPosition = $target1Pos * $normalizedWeights[0] + </p><p>                          $target2Pos * $normalizedWeights[1] + </p><p>                          $target3Pos * $normalizedWeights[2];</p><p>object.translateX = $blendedPosition.x;</p><p>object.translateY = $blendedPosition.y;</p><p>object.translateZ = $blendedPosition.z;</p></li></ul></li><li><p>Advanced Practical - orients an object based on the weighted influence of multiple joints, with weights determined by proximity</p><ul><li><p>vector $jointOrientations[];</p><p>$jointOrientations[0] = &lt;&lt;joint1.rotateX, joint1.rotateY, joint1.rotateZ&gt;&gt;;</p><p>$jointOrientations[1] = &lt;&lt;joint2.rotateX, joint2.rotateY, joint2.rotateZ&gt;&gt;;</p><p>$jointOrientations[2] = &lt;&lt;joint3.rotateX, joint3.rotateY, joint3.rotateZ&gt;&gt;;</p><p>float $distances[];</p><p>$distances[0] = mag(&lt;&lt;object.translateX - joint1.translateX, object.translateY - joint1.translateY, object.translateZ - joint1.translateZ&gt;&gt;);</p><p>$distances[1] = mag(&lt;&lt;object.translateX - joint2.translateX, object.translateY - joint2.translateY, object.translateZ - joint2.translateZ&gt;&gt;);</p><p>$distances[2] = mag(&lt;&lt;object.translateX - joint3.translateX, object.translateY - joint3.translateY, object.translateZ - joint3.translateZ&gt;&gt;);</p><p>float $weights[] = {1/$distances[0], 1/$distances[1], 1/$distances[2]};</p><p>float $normalizedWeights[] = normalizearray($weights);</p><p>vector $blendedOrientation = $jointOrientations[0] * $normalizedWeights[0] + </p><p>                             $jointOrientations[1] * $normalizedWeights[1] + </p><p>                             $jointOrientations[2] * $normalizedWeights[2];</p><p>object.rotateX = $blendedOrientation.x;</p><p>object.rotateY = $blendedOrientation.y;</p><p>object.rotateZ = $blendedOrientation.z;</p></li></ul></li></ul><p><strong>NormalizeWeightsArray</strong></p><ul><li><p>Same as normalize array, but it treats any negative number as 0.  Scales an array of values so that they sum to 1 while maintaining their relative proportions, with special handling for negative or 0 values.</p></li><li><p>Syntax: normalizeweights(array)</p></li><li><p>Functionality:</p><ul><li><p>Takes an array of numeric values as an input</p></li><li><p>Returns an array the same length where all positive values sum to 1</p></li><li><p>Maintains the relative proportions of the positive input values</p></li><li><p>Treats negative values as 0</p></li><li><p>If all values are 0 or negative, returns an array of equal positive values that sum to 1</p></li></ul></li><li><p>Example:</p><ul><li><p>float $inputArray[] = {2, 3, -1, 5};</p><p>float $normalizedArray[] = normalizeweights($inputArray);</p><p>// $normalizedArray will be approximately {0.2, 0.3, 0, 0.5}</p></li></ul></li><li><p>Practical - constraint where an object is influenced by three targets with normalized weights, safely handling negative or zero inputs</p><ul><li><p>vector $target1Pos = &lt;&lt;target1.translateX, target1.translateY, target1.translateZ&gt;&gt;;</p><p>vector $target2Pos = &lt;&lt;target2.translateX, target2.translateY, target2.translateZ&gt;&gt;;</p><p>vector $target3Pos = &lt;&lt;target3.translateX, target3.translateY, target3.translateZ&gt;&gt;;</p><p>float $weights[] = {control.weight1, control.weight2, control.weight3};</p><p>float $normalizedWeights[] = normalizeweights($weights);</p><p>vector $blendedPosition = $target1Pos * $normalizedWeights[0] + </p><p>                          $target2Pos * $normalizedWeights[1] + </p><p>                          $target3Pos * $normalizedWeights[2];</p><p>object.translateX = $blendedPosition.x;</p><p>object.translateY = $blendedPosition.y;</p><p>object.translateZ = $blendedPosition.z;</p></li></ul></li><li><p>Orients an object based on the weighted influence of multiple joints, safely handling cases where joints might coincide with the object.</p><ul><li><p>vector $jointOrientations[];</p><p>$jointOrientations[0] = &lt;&lt;joint1.rotateX, joint1.rotateY, joint1.rotateZ&gt;&gt;;</p><p>$jointOrientations[1] = &lt;&lt;joint2.rotateX, joint2.rotateY, joint2.rotateZ&gt;&gt;;</p><p>$jointOrientations[2] = &lt;&lt;joint3.rotateX, joint3.rotateY, joint3.rotateZ&gt;&gt;;</p><p>float $distances[];</p><p>$distances[0] = mag(&lt;&lt;object.translateX - joint1.translateX, object.translateY - joint1.translateY, object.translateZ - joint1.translateZ&gt;&gt;);</p><p>$distances[1] = mag(&lt;&lt;object.translateX - joint2.translateX, object.translateY - joint2.translateY, object.translateZ - joint2.translateZ&gt;&gt;);</p><p>$distances[2] = mag(&lt;&lt;object.translateX - joint3.translateX, object.translateY - joint3.translateY, object.translateZ - joint3.translateZ&gt;&gt;);</p><p>float $weights[] = {1/$distances[0], 1/$distances[1], 1/$distances[2]};</p><p>float $normalizedWeights[] = normalizeweights($weights);</p><p>vector $blendedOrientation = $jointOrientations[0] * $normalizedWeights[0] + </p><p>                             $jointOrientations[1] * $normalizedWeights[1] + </p><p>                             $jointOrientations[2] * $normalizedWeights[2];</p><p>object.rotateX = $blendedOrientation.x;</p><p>object.rotateY = $blendedOrientation.y;</p><p>object.rotateZ = $blendedOrientation.z;</p></li></ul></li></ul><p><strong>NotBool</strong></p><ul><li><p>Just checks to see if something is false</p></li><li><p>Syntax: x != y</p></li><li><p>Example:</p><ul><li><p>value = 1  # true</p><p>result = !value</p><p># result would be 0 (false)</p></li></ul></li></ul><p><strong>OrBool</strong></p><ul><li><p>Logical &#8220;or&#8221; comparison node</p></li><li><p>Syntax: x || y</p></li><li><p>Example:</p><ul><li><p>if (control1.active || control2.active) {</p><p>    visibility = 1;</p><p>} else {</p><p>    visibility = 0;</p><p>}</p></li></ul></li></ul><p><strong>Power</strong></p><ul><li><p>Raises a base number to a specified exponent</p></li><li><p>Syntax: power(base,exponent)</p></li><li><p>Functionality:</p><ul><li><p>Takes two inputs: the base and the exponent</p></li><li><p>Returns the result of base raised to the power of exponent</p></li></ul></li><li><p>Example:</p><ul><li><p>float $base = 2;</p><p>float $exponent = 3;</p><p>float $result = power($base, $exponent);</p><p>// $result would be 8 (2^3 = 2 * 2 * 2 = 8)</p></li></ul></li><li><p>Practical - creates an object that scales down exponentially as it moves away from a target</p><ul><li><p>vector $objectPos = &lt;&lt;object.translateX, object.translateY, object.translateZ&gt;&gt;;</p><p>vector $targetPos = &lt;&lt;target.translateX, target.translateY, target.translateZ&gt;&gt;;</p><p>float $distance = mag($targetPos - $objectPos);</p><p>float $maxDistance = 10;</p><p>float $minScale = 0.1;</p><p>float $falloffExponent = 2;</p><p>float $scaleFactor = power(1 - clamp($distance / $maxDistance, 0, 1), $falloffExponent);</p><p>float $finalScale = $minScale + (1 - $minScale) * $scaleFactor;</p><p>object.scaleX = $finalScale;</p><p>object.scaleY = $finalScale;</p><p>object.scaleZ = $finalScale;</p></li></ul></li><li><p>Advanced Practical - creates a smooth easing-in-and-out animation using a custom power-based easing function</p><ul><li><p>float $time = `currentTime -q`;</p><p>float $startTime = 1;</p><p>float $endTime = 120;</p><p>float $duration = $endTime - $startTime;</p><p>float $normalizedTime = ($time - $startTime) / $duration;</p><p>float $easedTime = power($normalizedTime, 3) * (1 - $normalizedTime) * 3 + power($normalizedTime, 3);</p><p>float $startValue = 0;</p><p>float $endValue = 10;</p><p>float $animatedValue = $startValue + ($endValue - $startValue) * $easedTime;</p><p>object.translateY = $animatedValue;</p></li></ul></li></ul><p><strong>QuaternionFrom</strong></p><ul><li><p>Converts an Euler Rotation or a rotation matrix into a quaternion.  Useful when dealing with complex rotation scenarios, continuous rotations, or when implementing smooth interpolations between orientations.</p></li><li><p>Variants:</p><ul><li><p>QuaternionFromRotation (Euler angles)</p></li><li><p>QuaternionFromMatrix (from a rotation matrix)</p></li></ul></li><li><p>Syntaxes: </p><ul><li><p>quat(rotation, rotation order) // for Euler</p></li><li><p>quat(matrix) for matrices</p></li></ul></li><li><p>Functionality:</p><ul><li><p>Takes rotation data as input (Euler with rotation order or a rotation matrix)</p></li><li><p>Returns a quaternion </p></li><li><p>Provides a gimbal-lock free representation of rotation</p></li></ul></li><li><p>Example</p><ul><li><p>vector $eulerRotation = &lt;&lt;30, 45, 60&gt;&gt;;  // In degrees</p><p>string $rotOrder = "xyz";</p><p>vector $quaternion = quat(deg_to_rad($eulerRotation), $rotOrder);</p><p>// $quaternion will be a 4D vector representing the quaternion</p></li></ul></li><li><p>Practical - Create a smooth interpolation between two rotations using quaternions</p><ul><li><p>vector $startRotation = &lt;&lt;object1.rotateX, object1.rotateY, object1.rotateZ&gt;&gt;;</p><p>vector $endRotation = &lt;&lt;object2.rotateX, object2.rotateY, object2.rotateZ&gt;&gt;;</p><p>vector $startQuat = quat(deg_to_rad($startRotation), "xyz");</p><p>vector $endQuat = quat(deg_to_rad($endRotation), "xyz");</p><p>float $blendFactor = control.blendAttr;  // Assume this ranges from 0 to 1</p><p>vector $resultQuat = slerp($startQuat, $endQuat, $blendFactor);</p><p>vector $finalRotation = rad_to_deg(rot($resultQuat, "xyz"));</p><p>object.rotateX = $finalRotation.x;</p><p>object.rotateY = $finalRotation.y;</p><p>object.rotateZ = $finalRotation.z;</p></li></ul></li><li><p>Advanced Practical - Create a weighted blend between three different orientation targets using quaternions</p><ul><li><p>vector $target1Rot = &lt;&lt;target1.rotateX, target1.rotateY, target1.rotateZ&gt;&gt;;</p><p>vector $target2Rot = &lt;&lt;target2.rotateX, target2.rotateY, target2.rotateZ&gt;&gt;;</p><p>vector $target3Rot = &lt;&lt;target3.rotateX, target3.rotateY, target3.rotateZ&gt;&gt;;</p><p>vector $quat1 = quat(deg_to_rad($target1Rot), "xyz");</p><p>vector $quat2 = quat(deg_to_rad($target2Rot), "xyz");</p><p>vector $quat3 = quat(deg_to_rad($target3Rot), "xyz");</p><p>float $weight1 = control.weight1;</p><p>float $weight2 = control.weight2;</p><p>float $weight3 = 1 - $weight1 - $weight2;</p><p>vector $blendQuat1 = slerp($quat1, $quat2, $weight2 / ($weight1 + $weight2));</p><p>vector $finalQuat = slerp($blendQuat1, $quat3, $weight3);</p><p>vector $finalRotation = rad_to_deg(rot($finalQuat, "xyz"));</p><p>object.rotateX = $finalRotation.x;</p><p>object.rotateY = $finalRotation.y;</p><p>object.rotateZ = $finalRotation.z;</p></li></ul></li></ul><p><strong>Remap</strong></p><ul><li><p>Scales a value from one range to another, maintaining the relative position of the value within the range.</p></li><li><p>Variants: </p><ul><li><p>Remap (float)</p></li><li><p>RemapInt (Int)</p></li><li><p>RemapAngle (Angle)</p></li></ul></li><li><p>Syntax: remap(value, oldMin, oldMax, newMin, newMax)</p></li><li><p>Functionality:</p><ul><li><p>Takes five inputs, the value to remap, the old range (min and max), the new range (min and max)</p></li><li><p>Returns the input value scaled to the new range</p></li><li><p>Performs linear interpolation between the ranges</p></li></ul></li><li><p>Example:</p><ul><li><p>float $input = 5;</p><p>float $result = remap($input, 0, 10, -1, 1);</p><p>// $result will be 0 (5 is halfway between 0 and 10, so it maps to halfway between -1 and 1)</p></li></ul></li><li><p>Practical - create a foot roll system where a single control attribute drives multiple joint rotations with appropriate ranges</p><ul><li><p>float $footRoll = foot_ctrl.roll;  // Assume this ranges from -1 to 1</p><p>// Heel rotation (active from -1 to 0)</p><p>heel.rotateX = remap($footRoll, -1, 0, -45, 0);</p><p>// Ball rotation (active from 0 to 0.5)</p><p>ball.rotateX = remap($footRoll, 0, 0.5, 0, 60);</p><p>// Toe rotation (active from 0.5 to 1)</p><p>toe.rotateX = remap($footRoll, 0.5, 1, 0, 30);</p></li></ul></li><li><p>Advanced Practical - Create a dynamic falloff effect where objects scale based on their distance from an effector.</p><ul><li><p>vector $objectPos = &lt;&lt;object.translateX, object.translateY, object.translateZ&gt;&gt;;</p><p>vector $effectorPos = &lt;&lt;effector.translateX, effector.translateY, effector.translateZ&gt;&gt;;</p><p>float $distance = mag($objectPos - $effectorPos);</p><p>float $innerRadius = effector.innerRadius;</p><p>float $outerRadius = effector.outerRadius;</p><p>float $falloff = 1 - remap($distance, $innerRadius, $outerRadius, 0, 1);</p><p>$falloff = clamp($falloff, 0, 1);</p><p>object.scaleX = lerp(1, 2, $falloff);</p><p>object.scaleY = lerp(1, 2, $falloff);</p><p>object.scaleZ = lerp(1, 2, $falloff);</p></li></ul></li></ul><p><strong>Round</strong></p><ul><li><p>Rounds a floating point value to the nearest integer, with anything above 0.5 going up and anything below 0.5 going down</p></li><li><p>Variants:</p><ul><li><p>Round (float)</p></li><li><p>RoundAngle (Angle)</p></li></ul></li><li><p>Syntax: round(value)</p></li><li><p>Functionality:</p><ul><li><p>Takes a floating point input</p></li><li><p>Returns the nearest integer value</p></li></ul></li><li><p>Example:</p><ul><li><p>float $value1 = 3.2;</p><p>float $value2 = 3.7;</p><p>float $result1 = round($value1);  // result1 will be 3</p><p>float $result2 = round($value2);  // result2 will be 4</p></li></ul></li></ul><p><strong>RotateVectorBy</strong></p><ul><li><p>Rotates a vector by a specified rotation (euler angles, quaternion or matrix)</p></li><li><p>Variants:</p><ul><li><p>RotateVectorByRotation (Euler)</p></li><li><p>RotateVectorByQuaternion (Quaternion)</p></li><li><p>RotateVectorByMatrix (Rotation Matrix)</p></li></ul></li><li><p>Syntax: </p><ul><li><p>rotate(vector,rotation,rotationOrder) //Euler</p></li><li><p>rotate(vector,quaternion) //Quaternion</p></li><li><p>rotate(vector,matrix) //Matricies</p></li></ul></li><li><p>Functionality</p><ul><li><p>Takes a vector and a rotation as an input</p></li><li><p>Returns the rotated vector</p></li><li><p>Allows precise control over vector orientation</p></li></ul></li><li><p>Example:</p><ul><li><p>vector $inputVector = &lt;&lt;1, 0, 0&gt;&gt;;  // Vector pointing along X-axis</p><p>vector $rotation = &lt;&lt;0, 90, 0&gt;&gt;;    // 90 degrees around Y-axis</p><p>vector $rotatedVector = rotate($inputVector, deg_to_rad($rotation), "xyz");</p><p>// $rotatedVector will be approximately &lt;&lt;0, 0, -1&gt;&gt;</p></li></ul></li></ul><p>Practical - Simple aim constraint with an up vector</p><ul><li><p>vector $objectPos = &lt;&lt;object.translateX, object.translateY, object.translateZ&gt;&gt;;</p><p>vector $targetPos = &lt;&lt;target.translateX, target.translateY, target.translateZ&gt;&gt;;</p><p>vector $upVector = &lt;&lt;0, 1, 0&gt;&gt;;  // World up vector</p><p>vector $aimVector = normalize($targetPos - $objectPos);</p><p>vector $rightVector = normalize(cross($aimVector, $upVector));</p><p>vector $newUpVector = cross($rightVector, $aimVector);</p><p>vector $forwardAxis = &lt;&lt;1, 0, 0&gt;&gt;;  // Local X-axis as forward</p><p>vector $upAxis = &lt;&lt;0, 1, 0&gt;&gt;;       // Local Y-axis as up</p><p>vector $rotationQuat = quatFromTwoVectors($forwardAxis, $aimVector) * quatFromTwoVectors($upAxis, $newUpVector);</p><p>vector $rotatedForward = rotate($forwardAxis, $rotationQuat);</p><p>vector $rotatedUp = rotate($upAxis, $rotationQuat);</p><p>vector $finalRotation = rot(rotationFromTwoVectors($rotatedForward, $rotatedUp), "xyz");</p><p>object.rotateX = rad_to_deg($finalRotation.x);</p><p>object.rotateY = rad_to_deg($finalRotation.y);</p><p>object.rotateZ = rad_to_deg($finalRotation.z);</p><p></p></li></ul><p><strong>RotationFrom</strong></p><ul><li><p>Converts a Quaternion or Matrix into Euler.  Its useful in scenarios where you need to convert between different rotation representations, implement space switching systems, or analyze the orientation of objects in complex hierarchies. </p></li><li><p>Variants:</p><ul><li><p>RotationFromMatrix (converts a matrix to euler angles)</p></li><li><p>RotationFromQuaternion (converts a quaternion to euler angles)</p></li></ul></li><li><p>Syntax: </p><ul><li><p>rot(matrix, rotationOrder)</p></li><li><p>rot(quaternion, rotationOrder)</p></li></ul></li><li><p>Functionality:</p><ul><li><p>Takes a matrix or quaternion as input</p></li><li><p>Returns a vector representing euler angles (in radians)</p></li><li><p>Allows specifying the desired rotation order</p></li></ul></li><li><p>Example:</p><ul><li><p>vector $matrix[4] = `object.worldMatrix`;</p><p>vector $eulerAngles = rot($matrix, "xyz");</p><p>// $eulerAngles will contain the rotation in radians</p></li></ul></li><li><p>Practical - Extracts the rotation from the target&#8217;s world matrix and applies it to the object in a simple orientation matching system:</p><ul><li><p>vector $targetMatrix[4] = `target.worldMatrix`;</p><p>vector $targetRotation = rot($targetMatrix, "xyz");</p><p>// Convert radians to degrees for Maya's rotate attributes</p><p>object.rotateX = rad_to_deg($targetRotation.x);</p><p>object.rotateY = rad_to_deg($targetRotation.y);</p><p>object.rotateZ = rad_to_deg($targetRotation.z);</p></li></ul></li><li><p>Practical Advanced - creating a space switching setup using matrix multiplication and rotation extraction</p><ul><li><p>vector $localMatrix[4] = `object.matrix`;</p><p>vector $parentWorldMatrix[4] = `parent.worldMatrix`;</p><p>vector $worldMatrix[4] = $parentWorldMatrix * $localMatrix;</p><p>int $spaceSwitch = control.spaceSwitch;  // Assume 0 for world, 1 for local</p><p>vector $resultMatrix[4];</p><p>if ($spaceSwitch == 0) $resultMatrix = $worldMatrix;</p><p>else $resultMatrix = $localMatrix;</p><p>vector $resultRotation = rot($resultMatrix, "xyz");</p><p>control.rotateX = rad_to_deg($resultRotation.x);</p><p>control.rotateY = rad_to_deg($resultRotation.y);</p><p>control.rotateZ = rad_to_deg($resultRotation.z);</p></li></ul></li></ul><p><strong>ScaleFromMatrix</strong></p><ul><li><p>Extracts the scale components from a transform matrix.  This is useful where you need to understand or compensate for scaling effects in a transformation hierarchy.  It&#8217;s a component in making scale-aware systems, maintaining consistent sizing across hierarchies, or implementing advanced constraint systems that need to account for parent scaling.</p></li><li><p>Syntax:  scale(matrix)</p></li><li><p>Functionality: </p><ul><li><p>Takes a 4x4 transformation matrix as input</p></li><li><p>Returns a vector representing the X, Y, and Z scale</p></li><li><p>Extracts scale even if the matrix includes rotation and scale</p></li></ul></li><li><p>Example:</p><ul><li><p>vector $localMatrix[4] = `object.matrix`;</p><p>vector $parentWorldMatrix[4] = `parent.worldMatrix`;</p><p>vector $worldMatrix[4] = $parentWorldMatrix * $localMatrix;</p><p>int $spaceSwitch = control.spaceSwitch;  // Assume 0 for world, 1 for local</p><p>vector $resultMatrix[4];</p><p>if ($spaceSwitch == 0) $resultMatrix = $worldMatrix;</p><p>else $resultMatrix = $localMatrix;</p><p>vector $resultRotation = rot($resultMatrix, "xyz");</p><p>control.rotateX = rad_to_deg($resultRotation.x);</p><p>control.rotateY = rad_to_deg($resultRotation.y);</p><p>control.rotateZ = rad_to_deg($resultRotation.z);</p></li></ul></li><li><p>Practical - a scale compensation system for a child object:</p><ul><li><p>vector $parentMatrix[4] = `parent.worldMatrix`;</p><p>vector $parentScale = scale($parentMatrix);</p><p>child.scaleX = 1 / $parentScale.x;</p><p>child.scaleY = 1 / $parentScale.y;</p><p>child.scaleZ = 1 / $parentScale.z;</p></li></ul></li><li><p>Advanced Practical - Creating a world-space scale indicator, taking into account all parent transformations:</p><ul><li><p>vector $localMatrix[4] = `object.matrix`;</p><p>vector $parentWorldMatrix[4] = `object.parentMatrix`;</p><p>vector $worldMatrix[4] = $parentWorldMatrix * $localMatrix;</p><p>vector $worldScale = scale($worldMatrix);</p><p>scaleIndicator.scaleX = $worldScale.x;</p><p>scaleIndicator.scaleY = $worldScale.y;</p><p>scaleIndicator.scaleZ = $worldScale.z;</p></li></ul></li></ul><p><strong>Select</strong></p><ul><li><p>Chooses between two values based on a conditional input.  Its useful for implementing logic-based systems, creating toggles between different states of behaviors, and designing more complex decision-making structures in your rigs.</p></li><li><p>Variants:</p><ul><li><p>Select (float)</p></li><li><p>SelectInt(Int)</p></li><li><p>SelectAngle (Angle)</p></li><li><p>SelectVector (Vector)</p></li><li><p>SelectMatrix (Matrix)</p></li></ul></li><li><p>Syntax: select(value1, value2, condition)</p></li><li><p>Functionality:</p><ul><li><p>Takes three inputs: two values and a condition</p></li><li><p>If the condition is true (non-zero) it returns a value 1</p></li><li><p>If the condition is false (zero) it returns value 2</p></li></ul></li><li><p>Example:</p><ul><li><p>float $control = node.control;  // Assume this is a 0 or 1 value</p><p>float $value1 = 5;</p><p>float $value2 = 10;</p><p>float $result = select($value1, $value2, $control);</p><p>// If $control is 1, $result will be 5</p><p>// If $control is 0, $result will be 10</p></li></ul></li><li><p>Practical - Switch the Y-rotation of the driven object between two different drivers:</p><ul><li><p>float $switch = control.switch;  // Assume this is a 0 or 1 value</p><p>float $rotation1 = driver1.rotateY;</p><p>float $rotation2 = driver2.rotateY;</p><p>driven.rotateY = select($rotation1, $rotation2, $switch);</p></li></ul></li><li><p>Advanced Practical - Creates a system where an object moves between four positions based on a single state control:</p><ul><li><p>float $state = control.state;  // Assume this ranges from 0 to 3</p><p>vector $pos1 = &lt;&lt;0, 0, 0&gt;&gt;;</p><p>vector $pos2 = &lt;&lt;10, 0, 0&gt;&gt;;</p><p>vector $pos3 = &lt;&lt;0, 10, 0&gt;&gt;;</p><p>vector $pos4 = &lt;&lt;0, 0, 10&gt;&gt;;</p><p>vector $selectedPos = select(</p><p>    select(</p><p>        select($pos1, $pos2, $state &gt; 0),</p><p>        $pos3,</p><p>        $state &gt; 1</p><p>    ),</p><p>    $pos4,</p><p>    $state &gt; 2</p><p>);</p><p>object.translateX = $selectedPos.x;</p><p>object.translateY = $selectedPos.y;</p><p>object.translateZ = $selectedPos.z;</p></li></ul></li></ul><p><strong>SelectArray</strong></p><ul><li><p>Chooses between two arrays of values based on a conditional input - essentially the same as select but dealing with arrays.  This is useful when you need to switch between multiple related values simultaneously.  It allows for cleaner expressions when dealint with data sets, such as poses, transformations, or any multi-attribute states.</p></li><li><p>Variants:</p><ul><li><p>SelectArray (float array)</p></li><li><p>SelectIntArray (int array)</p></li><li><p>SelectVectorArray (vector array)</p></li><li><p>SelectMatrixArray (matrix array)</p></li></ul></li><li><p>Syntax: selectarray(array1,array2,condition)</p></li><li><p>Functionality:</p><ul><li><p>Takes three inputs: two arrays of the same type and length, and a condition</p></li><li><p>If the condition is true (non-zero) it returns array 1</p></li><li><p>If the condition is false (zero), it returns array 2</p></li></ul></li><li><p>Example:</p><ul><li><p>float $control = node.control;  // Assume this is a 0 or 1 value</p><p>float $array1[] = {1, 2, 3, 4};</p><p>float $array2[] = {5, 6, 7, 8};</p><p>float $result[] = selectarray($array1, $array2, $control);</p><p>// If $control is 1, $result will be {1, 2, 3, 4}</p><p>// If $control is 0, $result will be {5, 6, 7, 8}</p></li></ul></li><li><p>Practical - Switches the rotation of three joints between two predefined poses based on the switch value</p><ul><li><p>float $switch = control.switch;  // Assume this is a 0 or 1 value</p><p>vector $pose1[] = {&lt;&lt;0,0,0&gt;&gt;, &lt;&lt;30,0,0&gt;&gt;, &lt;&lt;-30,0,0&gt;&gt;};</p><p>vector $pose2[] = {&lt;&lt;0,30,0&gt;&gt;, &lt;&lt;0,-30,0&gt;&gt;, &lt;&lt;0,0,30&gt;&gt;};</p><p>vector $selectedPose[] = selectarray($pose1, $pose2, $switch);</p><p>joint1.rotate = $selectedPose[0];</p><p>joint2.rotate = $selectedPose[1];</p><p>joint3.rotate = $selectedPose[2];</p></li></ul></li><li><p>Advanced Practical - Creates an FK/IK switch system for a chain of joints, switching between FK and IK positions based on a blend attribute</p><ul><li><p>float $ikFkBlend = control.ikFkBlend;  // Assume this ranges from 0 to 1</p><p>vector $fkPositions[] = {&lt;&lt;fk1.translateX, fk1.translateY, fk1.translateZ&gt;&gt;,</p><p>                         &lt;&lt;fk2.translateX, fk2.translateY, fk2.translateZ&gt;&gt;,</p><p>                         &lt;&lt;fk3.translateX, fk3.translateY, fk3.translateZ&gt;&gt;};</p><p>vector $ikPositions[] = {&lt;&lt;ik1.translateX, ik1.translateY, ik1.translateZ&gt;&gt;,</p><p>                         &lt;&lt;ik2.translateX, ik2.translateY, ik2.translateZ&gt;&gt;,</p><p>                         &lt;&lt;ik3.translateX, ik3.translateY, ik3.translateZ&gt;&gt;};</p><p>vector $blendedPositions[] = selectarray($ikPositions, $fkPositions, $ikFkBlend &gt; 0.5);</p><p>for ($i = 0; $i &lt; size($blendedPositions); $i++) {</p><p>    setAttr ("joint" + ($i+1) + ".translateX") $blendedPositions[$i].x;</p><p>    setAttr ("joint" + ($i+1) + ".translateY") $blendedPositions[$i].y;</p><p>    setAttr ("joint" + ($i+1) + ".translateZ") $blendedPositions[$i].z;</p><p>}</p></li></ul></li></ul><p><strong>SinAngle</strong></p><ul><li><p>Calculates the sine of an input angle.  Its useful in generating wave-like behaviors, circular movements, and in solving various trigonometric problems.  </p></li><li><p>Syntax:  sin(angle)</p></li><li><p>Functionality:</p><ul><li><p>Takes an angle as input (in radians)</p></li><li><p>Returns the sine of that angle (a value between -1 and 1)</p></li><li><p>Works with float values</p></li></ul></li><li><p>Example: </p><ul><li><p>float $angleInDegrees = 30;</p><p>float $angleInRadians = deg_to_rad($angleInDegrees);</p><p>float $result = sin($angleInRadians);</p><p>// $result will be approximately 0.5</p></li></ul></li><li><p>Practical - Creates a smooth, sinusoidal up-and-down motion for an object</p><ul><li><p>float $time = `currentTime -q`;</p><p>float $frequency = 0.1;  // Controls how fast the oscillation occurs</p><p>float $amplitude = 5;    // Controls the height of the oscillation</p><p>float $yPosition = $amplitude * sin($time * $frequency);</p><p>object.translateY = $yPosition;</p></li></ul></li><li><p>Advanced Practical - Creates a spiral motion that combines circular movement in the XZ plane with a steady upward motion:</p><ul><li><p>float $time = `currentTime -q`;</p><p>float $speed = 0.1;</p><p>float $radius = 5;</p><p>float $height = 0.1;</p><p>float $angle = $time * $speed;</p><p>float $xPosition = $radius * sin($angle);</p><p>float $zPosition = $radius * cos($angle);</p><p>float $yPosition = $height * $angle;</p><p>object.translateX = $xPosition;</p><p>object.translateY = $yPosition;</p><p>object.translateZ = $zPosition;</p></li></ul></li></ul><p><strong>SlerpQuaternion</strong></p><ul><li><p>Performs Spherical Linear Interpolation between two quaternions.   Useful where smooth and predictable rotation interpolations are crucial.  It blends between orientations in a way that avoids the problems associated with linear interpolation of euler angles, such as gimbal lock and non-uniform angular velocities.  </p></li><li><p>Syntax: slerp(quaternion1,quaternion2,weight)</p></li><li><p>Functionality:</p><ul><li><p>Takes two quaternions and an interpolation weight as input</p></li><li><p>Returns a quaternion that represents a smooth interpolation between the two input quaternions</p></li><li><p>The weight determines the blend between the two quaternions.</p></li></ul></li><li><p>Example: </p><ul><li><p>vector $quat1 = &lt;&lt;0, 0, 0, 1&gt;&gt;;  // Identity quaternion</p><p>vector $quat2 = &lt;&lt;0, 0.7071, 0, 0.7071&gt;&gt;;  // 90-degree rotation around Y</p><p>float $blend = 0.5;  // Halfway between the two rotations</p><p>vector $resultQuat = slerp($quat1, $quat2, $blend);</p></li></ul></li><li><p>Practical - Creates a smooth rotation from one object&#8217;s orientation to another as the blend attribute goes from 0 to 1</p><ul><li><p>vector $startRot = &lt;&lt;object1.rotateX, object1.rotateY, object1.rotateZ&gt;&gt;;</p><p>vector $endRot = &lt;&lt;object2.rotateX, object2.rotateY, object2.rotateZ&gt;&gt;;</p><p>vector $startQuat = quat(deg_to_rad($startRot), "xyz");</p><p>vector $endQuat = quat(deg_to_rad($endRot), "xyz");</p><p>float $blend = control.blendAttr;  // Assume this is a 0-1 slider</p><p>vector $interpolatedQuat = slerp($startQuat, $endQuat, $blend);</p><p>// Convert back to Euler angles for Maya's rotate attributes</p><p>vector $resultRotation = rad_to_deg(rot($interpolatedQuat, "xyz"));</p><p>object.rotateX = $resultRotation.x;</p><p>object.rotateY = $resultRotation.y;</p><p>object.rotateZ = $resultRotation.z;</p></li></ul></li><li><p>Advanced Practical - Creates a weighted blend between three different orientation targets using SLERP:</p><ul><li><p>vector $target1Rot = &lt;&lt;target1.rotateX, target1.rotateY, target1.rotateZ&gt;&gt;;</p><p>vector $target2Rot = &lt;&lt;target2.rotateX, target2.rotateY, target2.rotateZ&gt;&gt;;</p><p>vector $target3Rot = &lt;&lt;target3.rotateX, target3.rotateY, target3.rotateZ&gt;&gt;;</p><p>vector $quat1 = quat(deg_to_rad($target1Rot), "xyz");</p><p>vector $quat2 = quat(deg_to_rad($target2Rot), "xyz");</p><p>vector $quat3 = quat(deg_to_rad($target3Rot), "xyz");</p><p>float $weight1 = control.weight1;</p><p>float $weight2 = control.weight2;</p><p>float $weight3 = 1 - $weight1 - $weight2;</p><p>vector $blendQuat1 = slerp($quat1, $quat2, $weight2 / ($weight1 + $weight2));</p><p>vector $finalQuat = slerp($blendQuat1, $quat3, $weight3);</p><p>vector $finalRotation = rad_to_deg(rot($finalQuat, "xyz"));</p><p>object.rotateX = $finalRotation.x;</p><p>object.rotateY = $finalRotation.y;</p><p>object.rotateZ = $finalRotation.z;</p></li></ul></li></ul><p><strong>SmoothStep</strong></p><ul><li><p>Performs smooth Hermite interpolation between 0 and 1, creating an S-shaped curve.  Useful for creating natural-feeling transitions and easing effects.  It adds an organic feeling to linear inputs, making controls and animations feel less mechanical and more fluid.  Often used in user interface elements, blend shapes, constraint weights, and any scenario where a smooth, S-curved transition between two states is desirable.</p></li><li><p>Syntax: smoothstep(x)</p></li><li><p>Functionality: </p><ul><li><p>Takes a value between 0 and 1 as an input</p></li><li><p>Returns a smoothly interpolated value between 0 and 1</p></li><li><p>Provides an S-shaped curve that starts slow, accelerates in the middle, and slows down at the end.</p></li></ul></li><li><p>Example: </p><ul><li><p>float $input = 0.5;</p><p>float $result = smoothstep($input);</p><p>// $result will be 0.5, but with a different rate of change compared to the input</p></li></ul></li><li><p>Practical - Creates a visibility fade that starts and ends gradually, with a faster transition in the middle</p><ul><li><p>float $fadeControl = control.fade;  // Assume this ranges from 0 to 1</p><p>float $smoothFade = smoothstep($fadeControl);</p><p>object.visibility = $smoothFade;</p></li></ul></li><li><p>Advanced Practical - Creates a smooth animation that eases in and out over the specified duration:</p><ul><li><p>float $time = `currentTime -q`;</p><p>float $duration = 120;  // Animation duration in frames</p><p>float $normalizedTime = clamp($time / $duration, 0, 1);</p><p>float $smoothProgress = smoothstep($normalizedTime);</p><p>float $startValue = 0;</p><p>float $endValue = 10;</p><p>float $animatedValue = $startValue + ($endValue - $startValue) * $smoothProgress;</p><p>object.translateY = $animatedValue;</p></li></ul></li></ul><p><strong>Subtract</strong></p><ul><li><p>Subtracts one value from another</p></li><li><p>Syntax: x - y</p></li><li><p>Example:</p><ul><li><p>float $value1 = 10;</p><p>float $value2 = 3;</p><p>float $result = $value1 - $value2;</p><p>// $result will be 7</p></li></ul></li><li><p>Practical - a simple follow behavior with an offset</p><ul><li><p>vector $targetPos = &lt;&lt;target.translateX, target.translateY, target.translateZ&gt;&gt;;</p><p>vector $offsetVector = &lt;&lt;offset.translateX, offset.translateY, offset.translateZ&gt;&gt;;</p><p>vector $followPos = $targetPos - $offsetVector;</p><p>object.translateX = $followPos.x;</p><p>object.translateY = $followPos.y;</p><p>object.translateZ = $followPos.z;</p></li></ul></li></ul><p><strong>Sum</strong></p><ul><li><p>Used to add multiple values (more than two) stored in an array&#8217;</p></li><li><p>Syntax: sum([x,y,z,&#8230;])</p></li><li><p>Example:</p><ul><li><p>float $values[] = {1, 2, 3, 4, 5};</p><p>float $result = sum($values);</p><p>// $result will be 15</p></li></ul></li><li><p>Practical - multi-influence blending system from multiple targets</p><ul><li><p>float $weights[] = {control1.weight, control2.weight, control3.weight};</p><p>float $totalWeight = sum($weights);</p><p>if ($totalWeight &gt; 0) {</p><p>    vector $targetPos1 = &lt;&lt;target1.translateX, target1.translateY, target1.translateZ&gt;&gt;;</p><p>    vector $targetPos2 = &lt;&lt;target2.translateX, target2.translateY, target2.translateZ&gt;&gt;;</p><p>    vector $targetPos3 = &lt;&lt;target3.translateX, target3.translateY, target3.translateZ&gt;&gt;;</p><p>    vector $blendedPos = ($targetPos1 * $weights[0] + $targetPos2 * $weights[1] + $targetPos3 * $weights[2]) / $totalWeight;</p><p>    object.translateX = $blendedPos.x;</p><p>    object.translateY = $blendedPos.y;</p><p>    object.translateZ = $blendedPos.z;</p><p>}</p></li></ul></li></ul><p><strong>TanAngle</strong></p><ul><li><p>Calculates the tangent of an input angle.  It is used less frequently but has applications in creating certain types of motion curves, solving angular problems, and designing specialized mathematical relationships to rigs.  Its tendency to produce extreme values near certain angles can be either a challenge or a feature, depending on the desired behavior.</p></li><li><p>Syntax: tan(angle)</p></li><li><p>Functionality:</p><ul><li><p>Takes an angle as input (in radians)</p></li><li><p>Returns the tangent of that angle</p></li><li><p>Works with float values</p></li></ul></li><li><p>Example:</p><ul><li><p>float $time = `currentTime -q`;</p><p>float $duration = 120;  // Animation duration in frames</p><p>float $normalizedTime = clamp($time / $duration, 0, 1);</p><p>float $smoothProgress = smoothstep($normalizedTime);</p><p>float $startValue = 0;</p><p>float $endValue = 10;</p><p>float $animatedValue = $startValue + ($endValue - $startValue) * $smoothProgress;</p><p>object.translateY = $animatedValue;</p></li></ul></li><li><p>Practical - Creates a control that rotates faster as it approaches 90&#176;, due to the nature of the tangent function:</p><ul><li><p>float $inputRotation = joint.rotateX;  // Assume this is in degrees</p><p>float $inputRadians = deg_to_rad($inputRotation);</p><p>float $exaggeratedRotation = rad_to_deg(atan(tan($inputRadians) * 2));</p><p>control.rotateX = $exaggeratedRotation;</p></li></ul></li><li><p>Advanced Practical - Creates a rotation behavior that snaps to the nearest 15&#176; increment, with a smooth transition between snaps:</p><ul><li><p>float $inputRotation = joint.rotateX;  // Assume this is in degrees</p><p>float $inputRadians = deg_to_rad($inputRotation);</p><p>float $exaggeratedRotation = rad_to_deg(atan(tan($inputRadians) * 2));</p><p>control.rotateX = $exaggeratedRotation;</p></li></ul></li></ul><p><strong>TranslationFromMatrix</strong></p><ul><li><p>Extracts the translation component from a transformation matrix, making it possible to create rigs that can adapt to different coordinate spaces and parent-child relationships.  This fucntion is particularly useful in creating advanced constraints, space switching systems and any rig component that needs to understand and respond to the positions of the objects in various coordinate spaces.</p></li><li><p>Syntax: translation(matrix)</p></li><li><p>Functionality:</p><ul><li><p>Takes a 4x4 transformation matrix as input</p></li><li><p>Returns a vector representing the X, Y, and Z translation components</p></li><li><p>Extracts translation even if the matrix includes rotation and scale</p></li></ul></li><li><p>Example:</p><ul><li><p>vector $matrix[4] = `object.worldMatrix`;</p><p>vector $position = translation($matrix);</p><p>// $position will contain the X, Y, and Z world space position</p></li></ul></li><li><p>Practical - Makes an object follow the world space position of a target:</p><ul><li><p>vector $targetMatrix[4] = `target.worldMatrix`;</p><p>vector $targetPosition = translation($targetMatrix);</p><p>object.translateX = $targetPosition.x;</p><p>object.translateY = $targetPosition.y;</p><p>object.translateZ = $targetPosition.z;</p></li></ul></li><li><p>Advanced Practical - Offsets an object&#8217;s position in its local space, regardless of parent transformations</p><ul><li><p>vector $objectMatrix[4] = `object.matrix`;</p><p>vector $parentWorldMatrix[4] = `object.parentMatrix`;</p><p>vector $offsetVector = &lt;&lt;5, 0, 0&gt;&gt;;  // 5 units offset in X</p><p>vector $localOffset = inverse($parentWorldMatrix) * $offsetVector;</p><p>vector $currentPosition = translation($objectMatrix);</p><p>vector $newPosition = $currentPosition + $localOffset;</p><p>object.translateX = $newPosition.x;</p><p>object.translateY = $newPosition.y;</p><p>object.translateZ = $newPosition.z;</p></li></ul></li></ul><p><strong>TwistFrom</strong></p><ul><li><p>Extracts the twist rotation around a specific axis from a rotation or matrix output.  Allows riggers to isolate and manipulate specific aspects of rotation, which is crucial for creating natural-looking deformations in areas like arms, legs, and spines.  By extracting and redistributing twist, riggers can create more nuanced and anatomically correct motion in their character rigs.</p></li><li><p>Variants:</p><ul><li><p>TwistFromRotation (Extracts twist from euler angles)</p></li><li><p>TwistFromMatrix (Extracts twist from a transformation matrix)</p></li></ul></li><li><p>Syntax: </p><ul><li><p>twist(rotation, axis, rotationOrder) // for euler angles</p></li><li><p>twist(matrix, axis) // for matrices</p></li></ul></li><li><p>Functionality:</p><ul><li><p>Takes a rotation (euler angles or matrix) as input</p></li><li><p>Requires specification of the twist axis (0 for X, 1 for Y, 2 for Z)</p></li><li><p>Returns the angle of twist around the specified axis</p></li><li><p>For Euler angles, also requires the rotation order</p></li></ul></li><li><p>Example: </p><ul><li><p>vector $rotation = &lt;&lt;30, 45, 60&gt;&gt;;  // Rotation in degrees</p><p>float $twistAngle = twist(deg_to_rad($rotation), 1, "xyz");  // Extract twist around Y-axis</p><p>// $twistAngle will be in radians</p></li></ul></li><li><p>Practical - Extracts the twist of the hand relative to the upper arm and applies half of it to the forearm</p><ul><li><p>vector $upperArmMatrix[4] = `upperArm.worldMatrix`;</p><p>vector $handMatrix[4] = `hand.worldMatrix`;</p><p>float $twistAngle = twist($handMatrix, 0);  // Assuming X is the twist axis</p><p>// Apply a portion of the twist to the forearm</p><p>forearm.rotateX = rad_to_deg($twistAngle * 0.5);  // 50% of the twist</p></li></ul></li><li><p>Advanced Practical - Creates a multi-segment twist distribution for the spine evenly across multiple joints:</p><ul><li><p>vector $hipsMatrix[4] = `hips.worldMatrix`;</p><p>vector $chestMatrix[4] = `chest.worldMatrix`;</p><p>float $totalTwist = twist($chestMatrix, 1);  // Assuming Y is up</p><p>int $numSegments = 5;</p><p>float $twistPerSegment = $totalTwist / $numSegments;</p><p>for ($i = 1; $i &lt;= $numSegments; $i++) {</p><p>    float $segmentTwist = $twistPerSegment * $i;</p><p>    setAttr ("spineJoint" + $i + ".rotateY") rad_to_deg($segmentTwist);</p><p>}</p></li></ul></li></ul><p><strong>VectorLength</strong></p><ul><li><p>Caluculates the magnitude (length) of a vector</p></li><li><p>Example:</p><ul><li><p>vector $myVector = &lt;&lt;3, 4, 0&gt;&gt;;</p><p>float $magnitude = length($myVector);</p><p>// $magnitude will be 5</p></li></ul></li><li><p>In rigging you can</p><ul><li><p>Calculate the distance between objects</p></li><li><p>Normalize vectors</p></li><li><p>Implement scale based behaviors</p></li><li><p>create radius based effects or constraints</p></li></ul></li><li><p>Practical - Create a distance based scaling effect, where the scale decreases as the distance increases</p><ul><li><p>vector $objectPos = &lt;&lt;object.translateX, object.translateY, object.translateZ&gt;&gt;;</p><p>vector $targetPos = &lt;&lt;target.translateX, target.translateY, target.translateZ&gt;&gt;;</p><p>vector $difference = $targetPos - $objectPos;</p><p>float $distance = length($difference);</p><p>float $maxDistance = 10;</p><p>float $scale = 1 - clamp($distance / $maxDistance, 0, 1);</p><p>object.scaleX = $scale;</p><p>object.scaleY = $scale;</p><p>object.scaleZ = $scale;</p></li></ul></li><li><p>Advanced Practical - this creates a simple stretch effect for a middle joint based on a the overall length of a three joint chain</p><ul><li><p>vector $startPos = &lt;&lt;joint1.translateX, joint1.translateY, joint1.translateZ&gt;&gt;;</p><p>vector $endPos = &lt;&lt;joint3.translateX, joint3.translateY, joint3.translateZ&gt;&gt;;</p><p>float $currentLength = length($endPos - $startPos);</p><p>float $originalLength = joint2.originalLength; // Assume we stored this somewhere</p><p>float $stretchFactor = $currentLength / $originalLength;</p><p>joint2.scaleX = $stretchFactor;</p></li></ul></li></ul><p><strong>VectorLengthSquared</strong></p><ul><li><p>Calculates the sqared magnitude of a given vector without taking the square root. This is useful in situations where you need to work with distance based effects, but don&#8217;t need the exact linear distance.  By avoiding square root calculations, you can improve performance in rigs that involve many distance based calculations.  </p></li><li><p>Syntax: lengthsquared(vector)</p></li><li><p>Functionality:</p><ul><li><p>Takes a vector as an input</p></li><li><p>Returns a float representing the squared length of the vector</p></li><li><p>Calculates the sum of the squares of the vector components</p></li></ul></li><li><p>Example:</p><ul><li><p>vector $myVector = &lt;&lt;3, 4, 0&gt;&gt;;</p><p>float $magnitudeSquared = lengthsquared($myVector);</p><p>// $magnitudeSquared will be 25</p></li></ul></li><li><p>Practical - Toggles an object&#8217;s visibility based on its proximity to a target, using squared distance for efficiency</p><ul><li><p>vector $objectPos = &lt;&lt;object.translateX, object.translateY, object.translateZ&gt;&gt;;</p><p>vector $targetPos = &lt;&lt;target.translateX, target.translateY, target.translateZ&gt;&gt;;</p><p>vector $difference = $targetPos - $objectPos;</p><p>float $distanceSquared = lengthsquared($difference);</p><p>float $thresholdSquared = 100;  // 10 units squared</p><p>if ($distanceSquared &lt; $thresholdSquared) {</p><p>    object.visibility = 1;</p><p>} else {</p><p>    object.visibility = 0;</p><p>}</p></li></ul></li><li><p>Advanced Practical - Creates a scaling effect that falls off based on distance from a center point, using squared distances for better performance</p><ul><li><p>vector $centerPos = &lt;&lt;center.translateX, center.translateY, center.translateZ&gt;&gt;;</p><p>vector $objectPos = &lt;&lt;object.translateX, object.translateY, object.translateZ&gt;&gt;;</p><p>float $maxDistanceSquared = 400;  // 20 units squared</p><p>float $distanceSquared = lengthsquared($objectPos - $centerPos);</p><p>float $falloff = 1 - clamp($distanceSquared / $maxDistanceSquared, 0, 1);</p><p>object.scaleX = lerp(1, 2, $falloff);</p><p>object.scaleY = lerp(1, 2, $falloff);</p><p>object.scaleZ = lerp(1, 2, $falloff);</p></li></ul></li></ul><p><strong>WeightedAverage</strong></p><ul><li><p>Calculates the average of a set of values, with each value having its own weight.  It allows sophisticated multi-target constraints, smooth transitions between multiple states, and can be used to create dynamic, responsive rigs that adapt to multiple influences.</p></li><li><p>Variants:</p><ul><li><p>WeightedAverage (float)</p></li><li><p>WeightedAverageAngle (angle)</p></li><li><p>WeightedAverageInt (integer)</p></li><li><p>WeightedAverageVector (vector)</p></li><li><p>WeightedAverageMatrix (matrix)</p></li></ul></li><li><p>Syntax: weightedaverage(value1, weight1, value2, weight2, &#8230;)</p></li><li><p>Functionality:</p><ul><li><p>Takes pairs of values and weights</p></li><li><p>Returns the weighted average of the input values</p></li><li><p>Calculates (value1 * weight1 + value2 * weight2 + &#8230;) / (weight1 + weight2 + &#8230;)</p></li></ul></li><li><p>Example:</p><ul><li><p>float $value1 = 10;</p><p>float $weight1 = 2;</p><p>float $value2 = 20;</p><p>float $weight2 = 1;</p><p>float $result = weightedaverage($value1, $weight1, $value2, $weight2);</p><p>// $result will be 13.333... (40 / 3)</p></li></ul></li><li><p>Practical - Creates a position that&#8217;s a weighted blend of three target positions:</p><ul><li><p>vector $pos1 = &lt;&lt;target1.translateX, target1.translateY, target1.translateZ&gt;&gt;;</p><p>vector $pos2 = &lt;&lt;target2.translateX, target2.translateY, target2.translateZ&gt;&gt;;</p><p>vector $pos3 = &lt;&lt;target3.translateX, target3.translateY, target3.translateZ&gt;&gt;;</p><p>float $weight1 = control.weight1;</p><p>float $weight2 = control.weight2;</p><p>float $weight3 = control.weight3;</p><p>vector $blendedPos = weightedaverage($pos1, $weight1, $pos2, $weight2, $pos3, $weight3);</p><p>object.translateX = $blendedPos.x;</p><p>object.translateY = $blendedPos.y;</p><p>object.translateZ = $blendedPos.z;</p></li></ul></li><li><p>Advanced - A dynamic multi-joint orient constraint, where the influcence of each target is based on its distance from the object.</p><ul><li><p>vector $targetRot1 = &lt;&lt;target1.rotateX, target1.rotateY, target1.rotateZ&gt;&gt;;</p><p>vector $targetRot2 = &lt;&lt;target2.rotateX, target2.rotateY, target2.rotateZ&gt;&gt;;</p><p>vector $targetRot3 = &lt;&lt;target3.rotateX, target3.rotateY, target3.rotateZ&gt;&gt;;</p><p>float $distance1 = mag(&lt;&lt;object.translateX - target1.translateX, </p><p>                        object.translateY - target1.translateY, </p><p>                        object.translateZ - target1.translateZ&gt;&gt;);</p><p>float $distance2 = mag(&lt;&lt;object.translateX - target2.translateX, </p><p>                        object.translateY - target2.translateY, </p><p>                        object.translateZ - target2.translateZ&gt;&gt;);</p><p>float $distance3 = mag(&lt;&lt;object.translateX - target3.translateX, </p><p>                        object.translateY - target3.translateY, </p><p>                        object.translateZ - target3.translateZ&gt;&gt;);</p><p>float $weight1 = 1 / ($distance1 * $distance1);</p><p>float $weight2 = 1 / ($distance2 * $distance2);</p><p>float $weight3 = 1 / ($distance3 * $distance3);</p><p>vector $blendedRot = weightedaverage($targetRot1, $weight1, $targetRot2, $weight2, $targetRot3, $weight3);</p><p>object.rotateX = $blendedRot.x;</p><p>object.rotateY = $blendedRot.y;</p><p>object.rotateZ = $blendedRot.z;</p></li></ul></li></ul><p><strong>XorBool</strong></p><ul><li><p>Performs a logical XOR (exclusive OR) operation between two boolean values. It is useful in rigging scenarios where you need to create mutually exclusive behaviors or states.  Its handy when you need to trigger an action or state change based on the difference between two conditions, rather than their similarity. It performs a logical XOR (exclusive or) operation between two boolean values.</p></li><li><p>Variants:</p><ul><li><p>XorBool (for bools)</p></li><li><p>XorInt (for int values, treating non zero as true)</p></li></ul></li><li><p>Syntax: x ^ y (where &#8216;x&#8217; and &#8216;y&#8217; are boolean or int values to be compared)</p></li><li><p>Functionality:</p><ul><li><p>Takes two inputs</p></li><li><p>Returns true (1) if exactly one of the inputs is true, false (0) otherwise</p></li><li><p>Truth table:</p><ul><li><p>false XOR false = false</p></li><li><p>false XOR true = true</p></li><li><p>true XOR false = true</p></li><li><p>true XOR true = false</p></li></ul></li></ul></li><li><p>Example:</p><ul><li><p>int $value1 = control1.attribute &gt; 0;</p><p>int $value2 = control2.attribute &gt; 0;</p><p>int $result = $value1 ^ $value2;</p></li></ul></li><li><p>Practical - visibility toggle that&#8217;s on only when exactly one of the two controls is active:</p><ul><li><p>int $control1Active = control1.active;</p><p>int $control2Active = control2.active;</p><p>object.visibility = $control1Active ^ $control2Active;</p></li></ul></li><li><p>Advanced Practical - two-switch state machine, where three objects are exclusively visible based on the combination of two switches</p><ul><li><p>int $switch1 = control1.switch;</p><p>int $switch2 = control2.switch;</p><p>int $state1 = !$switch1 &amp;&amp; !$switch2;</p><p>int $state2 = $switch1 ^ $switch2;</p><p>int $state3 = $switch1 &amp;&amp; $switch2;</p><p>object1.visibility = $state1;</p><p>object2.visibility = $state2;</p><p>object3.visibility = $state3;</p></li></ul></li></ul>]]></content:encoded></item><item><title><![CDATA[Fun Animation Features]]></title><description><![CDATA[Notes]]></description><link>https://artofmaking.substack.com/p/fun-animation-features</link><guid isPermaLink="false">https://artofmaking.substack.com/p/fun-animation-features</guid><dc:creator><![CDATA[Annie Drake]]></dc:creator><pubDate>Wed, 22 May 2024 23:40:38 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!BhPU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F384e7f1e-e08b-4113-a6c2-86f9a98f4fe5_144x144.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Motion Matching</strong>:  Loading a library of animations into a data set.  Based on movement parameters you set up, (velocity and direction most common) UE5 will play the one whose movement most closely matches your movement.</p><p><strong>Animation Graph</strong>: Event Graph and Anim Graph live under the Anim Blueprint.  The Anim Graph handles animation specific connections and logic (state machines, poses, ect)</p><p><strong>Animation Blueprint</strong>: The Anim Blueprint handles all animation, and needs to be assigned under the character&#8217;s blueprint. </p><p><strong>Blendspace</strong>: This creates a 2D graph in which two values can be mapped (IE Position, orientation, velocity ect).  Animations can be dropped in a grid pattern depending on where that slider is in its intensity.</p><p><strong>Additive Animation</strong>: Adds two animation values together rather than overriding.  You could use this to lean when you reach fast speeds, create more dynamic reactions when you fall and hit the ground, ect.</p><p><strong>Animation Notifiers</strong>: An &#8220;event&#8221; you can put into an animation (examples: audio FX, Particle FX, Damage ect)</p><p><strong>Layered Blend per Bone</strong>: Play 2 animations on one skeleton - this lets you delegate which bone in the hierarchy the second animation begins playing at.  (IE if that bone is L clavical, the entire left arm will play animation #2, but the rest of the body will play animation #1)</p><p><strong>Blend Poses by Bool / Enum</strong>:  Attribute in Anim Graph, you can apply any movement sequence according to bool/enums.  Bool example - is falling play 1D blendspace (according to speed), upon hit ground bool turns off and return to standard motion space.</p><p><strong>State Machine</strong>: Series of nodes which contain animation states (idle, walking, death ect) and transition states.  You&#8217;ll load logic into the transition states, and animation rules into the states (blendspaces, enum state ect).</p><p><strong>Animation Montage</strong>: A great way to call one off animations, it has lots of options (play rate, start position, On Complete, On Blend Out, On Interrupt, On Notify Begin/End</p><p><strong>Physical Animation</strong>: Robust ragdoll, there are ways of blending animations with the ragdoll state to achieve looks (IE slight amount of ragdoll could make character look more &#8220;tired&#8221;, or you could apply ragdoll for taking hits, falling, then blend animations in before hitting the ground depending on fall direction to &#8220;catch&#8221; themselves and recover.</p><p><strong>Save Pose Snapshot</strong>: Lets you grab a pose in a moment.  This is helpful for transitioning from one system to another (Physical Animation would be a good use)</p><p><strong>Cached Animation</strong>: Its a way of grabbing a snapshot of a pose that you can feed into multiple different inputs.  This  only works in the Anim Graph, and not in state machines.</p><p><strong>Pose Assets</strong>:  Save out a series of poses from maya (starting on frame 0 incrementing every frame).  You can then load into Unreal as driven animation.  (Examples: Driving auto facial animation like Faceware, or shifting armor around depending on rotation of arm, or animating muscles or auxillary info like hair)</p>]]></content:encoded></item><item><title><![CDATA[Shader Principals]]></title><description><![CDATA[Notes - Feb 24 2024 Migrated from Tumblr]]></description><link>https://artofmaking.substack.com/p/shader-principals</link><guid isPermaLink="false">https://artofmaking.substack.com/p/shader-principals</guid><dc:creator><![CDATA[Annie Drake]]></dc:creator><pubDate>Mon, 04 Mar 2024 16:32:49 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!zvcG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F310e2a19-258c-4f0d-9eac-b1b5be9c1aa0_500x500.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2><strong>Normal Maps</strong></h2><p>Every pixel of a normal map gets a different direction. Front left is blue, front right is red. Back Left is yellow, back right is green. Up is lighter, down is darker. You would think then that normal maps would be multicolored, and model space normal maps are. We are more used to dealing with tangent space normal maps, however, which orient themselves locally to the direction of the normal.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zvcG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F310e2a19-258c-4f0d-9eac-b1b5be9c1aa0_500x500.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zvcG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F310e2a19-258c-4f0d-9eac-b1b5be9c1aa0_500x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!zvcG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F310e2a19-258c-4f0d-9eac-b1b5be9c1aa0_500x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!zvcG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F310e2a19-258c-4f0d-9eac-b1b5be9c1aa0_500x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!zvcG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F310e2a19-258c-4f0d-9eac-b1b5be9c1aa0_500x500.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zvcG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F310e2a19-258c-4f0d-9eac-b1b5be9c1aa0_500x500.jpeg" width="500" height="500" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/310e2a19-258c-4f0d-9eac-b1b5be9c1aa0_500x500.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:500,&quot;width&quot;:500,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Tangent Space&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Tangent Space" title="Tangent Space" srcset="https://substackcdn.com/image/fetch/$s_!zvcG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F310e2a19-258c-4f0d-9eac-b1b5be9c1aa0_500x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!zvcG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F310e2a19-258c-4f0d-9eac-b1b5be9c1aa0_500x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!zvcG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F310e2a19-258c-4f0d-9eac-b1b5be9c1aa0_500x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!zvcG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F310e2a19-258c-4f0d-9eac-b1b5be9c1aa0_500x500.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Tangent Space Normal Map</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!H9Dh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06ee467f-d94b-4408-9fee-03ec2386266e_448x448.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!H9Dh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06ee467f-d94b-4408-9fee-03ec2386266e_448x448.jpeg 424w, https://substackcdn.com/image/fetch/$s_!H9Dh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06ee467f-d94b-4408-9fee-03ec2386266e_448x448.jpeg 848w, https://substackcdn.com/image/fetch/$s_!H9Dh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06ee467f-d94b-4408-9fee-03ec2386266e_448x448.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!H9Dh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06ee467f-d94b-4408-9fee-03ec2386266e_448x448.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!H9Dh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06ee467f-d94b-4408-9fee-03ec2386266e_448x448.jpeg" width="448" height="448" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/06ee467f-d94b-4408-9fee-03ec2386266e_448x448.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:448,&quot;width&quot;:448,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Model Space&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Model Space" title="Model Space" srcset="https://substackcdn.com/image/fetch/$s_!H9Dh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06ee467f-d94b-4408-9fee-03ec2386266e_448x448.jpeg 424w, https://substackcdn.com/image/fetch/$s_!H9Dh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06ee467f-d94b-4408-9fee-03ec2386266e_448x448.jpeg 848w, https://substackcdn.com/image/fetch/$s_!H9Dh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06ee467f-d94b-4408-9fee-03ec2386266e_448x448.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!H9Dh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06ee467f-d94b-4408-9fee-03ec2386266e_448x448.jpeg 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Model Space Normal Ma</figcaption></figure></div><h2><strong>Dot Product</strong></h2><p>If you have two angles on a 2D plane, and took the first of the two vectors, you would have your dot product. The dot product essentially measures how much two vectors are pointing in the same direction. So if the angle between two normal directions were 90&#176;, the dot product would be 0, and if the angle were 0&#176; the dot product would be 1.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2SIB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452e5082-20c9-4193-9945-12cb9a1f0499_500x330.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2SIB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452e5082-20c9-4193-9945-12cb9a1f0499_500x330.png 424w, https://substackcdn.com/image/fetch/$s_!2SIB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452e5082-20c9-4193-9945-12cb9a1f0499_500x330.png 848w, https://substackcdn.com/image/fetch/$s_!2SIB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452e5082-20c9-4193-9945-12cb9a1f0499_500x330.png 1272w, https://substackcdn.com/image/fetch/$s_!2SIB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452e5082-20c9-4193-9945-12cb9a1f0499_500x330.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2SIB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452e5082-20c9-4193-9945-12cb9a1f0499_500x330.png" width="500" height="330" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/452e5082-20c9-4193-9945-12cb9a1f0499_500x330.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:330,&quot;width&quot;:500,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="image" title="image" srcset="https://substackcdn.com/image/fetch/$s_!2SIB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452e5082-20c9-4193-9945-12cb9a1f0499_500x330.png 424w, https://substackcdn.com/image/fetch/$s_!2SIB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452e5082-20c9-4193-9945-12cb9a1f0499_500x330.png 848w, https://substackcdn.com/image/fetch/$s_!2SIB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452e5082-20c9-4193-9945-12cb9a1f0499_500x330.png 1272w, https://substackcdn.com/image/fetch/$s_!2SIB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452e5082-20c9-4193-9945-12cb9a1f0499_500x330.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Game engines look for the relationship between lighting and materials. Indirect light approaches an object from all angles, direct light approaches from one. Diffuse materials reflect light in all directions, specular in one. The game engine views both the incoming light and reflected light as a normal, and mapping the relationship between the light and the material type is an example of how the dot product can be practically applied.</p><p>Of course, we are not in 2D space, were in 3D. Our vector which emanates directly from the face or vertex is our Normal (everyone knows that term) and the two vectors parallel to our face are our tangent and bitangent vectors. A perfectly neutral normal map (no deformation) would read with our tangent and bitangent values at 0, and our z tangent at 1.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DC2A!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495eebbe-1821-450c-bb13-61d1519b1d87_377x389.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DC2A!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495eebbe-1821-450c-bb13-61d1519b1d87_377x389.png 424w, https://substackcdn.com/image/fetch/$s_!DC2A!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495eebbe-1821-450c-bb13-61d1519b1d87_377x389.png 848w, https://substackcdn.com/image/fetch/$s_!DC2A!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495eebbe-1821-450c-bb13-61d1519b1d87_377x389.png 1272w, https://substackcdn.com/image/fetch/$s_!DC2A!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495eebbe-1821-450c-bb13-61d1519b1d87_377x389.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DC2A!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495eebbe-1821-450c-bb13-61d1519b1d87_377x389.png" width="377" height="389" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/495eebbe-1821-450c-bb13-61d1519b1d87_377x389.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:389,&quot;width&quot;:377,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="image" title="image" srcset="https://substackcdn.com/image/fetch/$s_!DC2A!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495eebbe-1821-450c-bb13-61d1519b1d87_377x389.png 424w, https://substackcdn.com/image/fetch/$s_!DC2A!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495eebbe-1821-450c-bb13-61d1519b1d87_377x389.png 848w, https://substackcdn.com/image/fetch/$s_!DC2A!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495eebbe-1821-450c-bb13-61d1519b1d87_377x389.png 1272w, https://substackcdn.com/image/fetch/$s_!DC2A!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495eebbe-1821-450c-bb13-61d1519b1d87_377x389.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!D0Gs!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e31bc5e-14ad-4963-b520-87e7d6131907_500x479.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!D0Gs!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e31bc5e-14ad-4963-b520-87e7d6131907_500x479.png 424w, https://substackcdn.com/image/fetch/$s_!D0Gs!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e31bc5e-14ad-4963-b520-87e7d6131907_500x479.png 848w, https://substackcdn.com/image/fetch/$s_!D0Gs!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e31bc5e-14ad-4963-b520-87e7d6131907_500x479.png 1272w, https://substackcdn.com/image/fetch/$s_!D0Gs!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e31bc5e-14ad-4963-b520-87e7d6131907_500x479.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!D0Gs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e31bc5e-14ad-4963-b520-87e7d6131907_500x479.png" width="388" height="371.704" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1e31bc5e-14ad-4963-b520-87e7d6131907_500x479.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:479,&quot;width&quot;:500,&quot;resizeWidth&quot;:388,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="image" title="image" srcset="https://substackcdn.com/image/fetch/$s_!D0Gs!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e31bc5e-14ad-4963-b520-87e7d6131907_500x479.png 424w, https://substackcdn.com/image/fetch/$s_!D0Gs!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e31bc5e-14ad-4963-b520-87e7d6131907_500x479.png 848w, https://substackcdn.com/image/fetch/$s_!D0Gs!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e31bc5e-14ad-4963-b520-87e7d6131907_500x479.png 1272w, https://substackcdn.com/image/fetch/$s_!D0Gs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e31bc5e-14ad-4963-b520-87e7d6131907_500x479.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2><strong>Lighting Vectors + Normal Vectors</strong></h2><p>A Direct Light pointing at a normal with a dot product of 0 will have full illumination, and a dot product of 1 will be unlit by that light. Adding a normal map into the equation essentially adds new vectors onto the surface as a map, which the light normals use to calculate how much that space on the object should receive light.</p><h2><strong>Fresnel</strong></h2><p>The amount of light reflected from an object is dependent on the viewing angle. If fresnel were on 100%, you would not see any reflection when looking strait at the object. As its normals moved away from you at a 90&#176; angle, the reflection would increase.</p><p>This is an effect which you would see in water, or when building a cloth shader.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!HIA7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F769cae23-6d96-4ef6-ad5f-858dbfb15879_470x453.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HIA7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F769cae23-6d96-4ef6-ad5f-858dbfb15879_470x453.png 424w, https://substackcdn.com/image/fetch/$s_!HIA7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F769cae23-6d96-4ef6-ad5f-858dbfb15879_470x453.png 848w, https://substackcdn.com/image/fetch/$s_!HIA7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F769cae23-6d96-4ef6-ad5f-858dbfb15879_470x453.png 1272w, https://substackcdn.com/image/fetch/$s_!HIA7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F769cae23-6d96-4ef6-ad5f-858dbfb15879_470x453.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HIA7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F769cae23-6d96-4ef6-ad5f-858dbfb15879_470x453.png" width="470" height="453" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/769cae23-6d96-4ef6-ad5f-858dbfb15879_470x453.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:453,&quot;width&quot;:470,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="image" title="image" srcset="https://substackcdn.com/image/fetch/$s_!HIA7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F769cae23-6d96-4ef6-ad5f-858dbfb15879_470x453.png 424w, https://substackcdn.com/image/fetch/$s_!HIA7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F769cae23-6d96-4ef6-ad5f-858dbfb15879_470x453.png 848w, https://substackcdn.com/image/fetch/$s_!HIA7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F769cae23-6d96-4ef6-ad5f-858dbfb15879_470x453.png 1272w, https://substackcdn.com/image/fetch/$s_!HIA7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F769cae23-6d96-4ef6-ad5f-858dbfb15879_470x453.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!CF0-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b8d8d4c-9ea2-4576-9f39-3b4d1c11c2a8_500x477.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!CF0-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b8d8d4c-9ea2-4576-9f39-3b4d1c11c2a8_500x477.jpeg 424w, https://substackcdn.com/image/fetch/$s_!CF0-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b8d8d4c-9ea2-4576-9f39-3b4d1c11c2a8_500x477.jpeg 848w, https://substackcdn.com/image/fetch/$s_!CF0-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b8d8d4c-9ea2-4576-9f39-3b4d1c11c2a8_500x477.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!CF0-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b8d8d4c-9ea2-4576-9f39-3b4d1c11c2a8_500x477.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!CF0-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b8d8d4c-9ea2-4576-9f39-3b4d1c11c2a8_500x477.jpeg" width="500" height="477" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2b8d8d4c-9ea2-4576-9f39-3b4d1c11c2a8_500x477.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:477,&quot;width&quot;:500,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="image" title="image" srcset="https://substackcdn.com/image/fetch/$s_!CF0-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b8d8d4c-9ea2-4576-9f39-3b4d1c11c2a8_500x477.jpeg 424w, https://substackcdn.com/image/fetch/$s_!CF0-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b8d8d4c-9ea2-4576-9f39-3b4d1c11c2a8_500x477.jpeg 848w, https://substackcdn.com/image/fetch/$s_!CF0-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b8d8d4c-9ea2-4576-9f39-3b4d1c11c2a8_500x477.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!CF0-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b8d8d4c-9ea2-4576-9f39-3b4d1c11c2a8_500x477.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2><strong>Reflectivity</strong></h2><p>Reflectivity of most objects is 4% - which maps to 0.5 (on a 0-1 float). A super reflective surface would be up to 8% (1), but all of these objects increase in their reflectivity as the Normals tilt away from the viewing angle. Most game engines come with reflectivity built in, by setting metallic to 1 and roughness to 0 you get it.</p><p>Under the hood, reflection is the 90&#176; angle from the viewing vector to the surface, and refraction is the 180&#176;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!H_B1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd0f9571-2201-4d35-95f1-32973e514c1a_500x303.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!H_B1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd0f9571-2201-4d35-95f1-32973e514c1a_500x303.png 424w, https://substackcdn.com/image/fetch/$s_!H_B1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd0f9571-2201-4d35-95f1-32973e514c1a_500x303.png 848w, https://substackcdn.com/image/fetch/$s_!H_B1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd0f9571-2201-4d35-95f1-32973e514c1a_500x303.png 1272w, https://substackcdn.com/image/fetch/$s_!H_B1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd0f9571-2201-4d35-95f1-32973e514c1a_500x303.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!H_B1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd0f9571-2201-4d35-95f1-32973e514c1a_500x303.png" width="500" height="303" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fd0f9571-2201-4d35-95f1-32973e514c1a_500x303.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:303,&quot;width&quot;:500,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="image" title="image" srcset="https://substackcdn.com/image/fetch/$s_!H_B1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd0f9571-2201-4d35-95f1-32973e514c1a_500x303.png 424w, https://substackcdn.com/image/fetch/$s_!H_B1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd0f9571-2201-4d35-95f1-32973e514c1a_500x303.png 848w, https://substackcdn.com/image/fetch/$s_!H_B1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd0f9571-2201-4d35-95f1-32973e514c1a_500x303.png 1272w, https://substackcdn.com/image/fetch/$s_!H_B1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd0f9571-2201-4d35-95f1-32973e514c1a_500x303.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2><strong>Refraction</strong></h2><p>As with the image above, the default value from the camera vector to the refraction is a strait line. Some objects have refraction on them, which bends the view angle slightly. To achieve refraction, you need to know your refractive index for your origin (viewing angle) and your target (model). <a href="https://en.wikipedia.org/wiki/List_of_refractive_indices">Wikipedia has a great page on refractive indices of objects</a>. Assuming you&#8217;re not viewing from inside water, the refractive index of air is 1, which would be your typical default. Your refractive index of say water, is 1.333. The graph above shows the refracted vertex bend appropriately.</p><p>To simulate a glass of water, you would apply a Fresnel effect to the reflection and refraction, where you would get a water refraction in the middle, and a reflection on the edge.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2mR2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84e2f9de-1d6a-429c-bcd6-0fdc4f25b665_274x206.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2mR2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84e2f9de-1d6a-429c-bcd6-0fdc4f25b665_274x206.png 424w, https://substackcdn.com/image/fetch/$s_!2mR2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84e2f9de-1d6a-429c-bcd6-0fdc4f25b665_274x206.png 848w, https://substackcdn.com/image/fetch/$s_!2mR2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84e2f9de-1d6a-429c-bcd6-0fdc4f25b665_274x206.png 1272w, https://substackcdn.com/image/fetch/$s_!2mR2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84e2f9de-1d6a-429c-bcd6-0fdc4f25b665_274x206.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2mR2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84e2f9de-1d6a-429c-bcd6-0fdc4f25b665_274x206.png" width="274" height="206" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/84e2f9de-1d6a-429c-bcd6-0fdc4f25b665_274x206.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:206,&quot;width&quot;:274,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="image" title="image" srcset="https://substackcdn.com/image/fetch/$s_!2mR2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84e2f9de-1d6a-429c-bcd6-0fdc4f25b665_274x206.png 424w, https://substackcdn.com/image/fetch/$s_!2mR2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84e2f9de-1d6a-429c-bcd6-0fdc4f25b665_274x206.png 848w, https://substackcdn.com/image/fetch/$s_!2mR2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84e2f9de-1d6a-429c-bcd6-0fdc4f25b665_274x206.png 1272w, https://substackcdn.com/image/fetch/$s_!2mR2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84e2f9de-1d6a-429c-bcd6-0fdc4f25b665_274x206.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ONkE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4173250b-2685-4a3e-95fc-f103f87736d1_474x634.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ONkE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4173250b-2685-4a3e-95fc-f103f87736d1_474x634.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ONkE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4173250b-2685-4a3e-95fc-f103f87736d1_474x634.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ONkE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4173250b-2685-4a3e-95fc-f103f87736d1_474x634.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ONkE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4173250b-2685-4a3e-95fc-f103f87736d1_474x634.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ONkE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4173250b-2685-4a3e-95fc-f103f87736d1_474x634.jpeg" width="474" height="634" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4173250b-2685-4a3e-95fc-f103f87736d1_474x634.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:634,&quot;width&quot;:474,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="image" title="image" srcset="https://substackcdn.com/image/fetch/$s_!ONkE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4173250b-2685-4a3e-95fc-f103f87736d1_474x634.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ONkE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4173250b-2685-4a3e-95fc-f103f87736d1_474x634.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ONkE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4173250b-2685-4a3e-95fc-f103f87736d1_474x634.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ONkE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4173250b-2685-4a3e-95fc-f103f87736d1_474x634.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h1><strong>Rendering: Real-Time Pre-Existing Methods vs. Raytracing</strong></h1><p>Raytracing is a rendering method which projects rays from the camera into the scene, and interprets the color of pixel. Shadows, AO, and Reflections require further bounces, which can bounce again, and so the number of rays which need to be calculated can become quite large; this it is a very computationally expensive method.</p><p>Rasterization is the typical real-time rendering method, which works the inverse (maps object to screen). It requires a lot of tricks and work to get things looking good, where raytracing calculates it automatically.</p><p>Unreal updates combine the two, using Rasterization for things like diffuse, blurred reflections, and Raytracing for things like sharp reflection. Ambient Occlusion and Shadows split which method they use.</p><h2><strong>Ambient Occlusion</strong></h2><p>Measures how much light is blocked from reaching certain parts of the object. AO is calculated by bouncing a number of rays from the point on the model they hit. If none of those secondary rays hit anything, then the point is unoccluded, and inversely the more that hit an object, the more that point is occluded. This is quite expensive, so Unreal uses a method called Temporal Accumulation, which reduces the number of bounces by sending them out in turns at different frames and averaging the results for its real-time raytracing.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!p8HO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F299b1c33-c684-4def-9253-3cb38d7e499d_500x237.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!p8HO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F299b1c33-c684-4def-9253-3cb38d7e499d_500x237.png 424w, https://substackcdn.com/image/fetch/$s_!p8HO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F299b1c33-c684-4def-9253-3cb38d7e499d_500x237.png 848w, https://substackcdn.com/image/fetch/$s_!p8HO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F299b1c33-c684-4def-9253-3cb38d7e499d_500x237.png 1272w, https://substackcdn.com/image/fetch/$s_!p8HO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F299b1c33-c684-4def-9253-3cb38d7e499d_500x237.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!p8HO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F299b1c33-c684-4def-9253-3cb38d7e499d_500x237.png" width="500" height="237" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/299b1c33-c684-4def-9253-3cb38d7e499d_500x237.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:237,&quot;width&quot;:500,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="image" title="image" srcset="https://substackcdn.com/image/fetch/$s_!p8HO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F299b1c33-c684-4def-9253-3cb38d7e499d_500x237.png 424w, https://substackcdn.com/image/fetch/$s_!p8HO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F299b1c33-c684-4def-9253-3cb38d7e499d_500x237.png 848w, https://substackcdn.com/image/fetch/$s_!p8HO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F299b1c33-c684-4def-9253-3cb38d7e499d_500x237.png 1272w, https://substackcdn.com/image/fetch/$s_!p8HO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F299b1c33-c684-4def-9253-3cb38d7e499d_500x237.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Previously AO was faked using Screen Space AO, which reconstructs the scene using the depth buffer. For each pixel on the screen it samples the depth of the surrounding pixels to determine if they are closer to the camera. This is fairly fast to compute but creates artifacts and isn&#8217;t perfectly accurate. For example, if the bottom of a chair is not in view of the camera, it will not be included in the depth buffer, and will not cast AO on the floor below it. Because Raytracing bounces around the scene, it can calculate against objects that are not in view of the camera, but whose effects would be seen on screen. (Like that edge case)</p><h2><strong>Reflections</strong></h2><p>There are many reflection methods, all of which have strengths and weaknesses. A nice feature of Unreal is that it if data is not available using one method, it will fall back to another.</p><p><strong>Light Probes:</strong> A light probe is an object in the scene which captures a cubemap from its position. If you&#8217;re within that cubemap&#8217;s radius the reflections you see reflect that cubemap. The obvious limitation being that you are not seeing the reflection from your point of view. Light Probes have to be setup by an artist, and anytime the scene changes they have to be re-baked, and they can only reflect static objects.</p><p><strong>Screen Space Reflections:</strong> Just like with AO, screen space calculates the depth buffer based on the camera viewpoint. Because you&#8217;re capturing your buffer from the camera POV, anything your camera can see can be reflected in the reflection, which means it captures more accurately to its position than Light Probes. A limitation is that it can only reflect what is on screen, so it does not capture elements outside the viewport (say behind the camera). If there are elements that cannot be captured via the screenspace method, the reflection falls back to the lightprobe. Because of the blindspots it creates strange effects at times due to the changing camera position.</p><p><strong>Raytracing</strong>: This corrects all issues and creates perfect, dynamic reflections with no baking involved. It works by shooting a ray from the camera, and when it hits a reflective surface, shooting another ray at a 90 angle. Sharp reflections will shoot a single ray, but the blurrier the reflection the more rays it shoots, in a cone shape.</p><p>In order to save on performance, Unreal creates a threshold of blurriness called max roughness, at which point it will switch to a blurred cubemap method.</p><p>Two other methods of minimizing the performance hit of real time reflection raytracing is by limiting the max bounces (number of times a ray can bounce before it dies), and turning off shadows in your reflections.</p><p><strong>Shadow</strong>:</p><p>Traditional method is called shadow mapping. This is where you render the scene from the POV of the light, and compare that to the POV of the camera. If there are parts of the scene that the camera can see but the light cannot, we assume they are in shadow.</p><p>Raytracing implements in the same way, but does away with a few visual glitches, and also allows for much better soft shadows.</p><p><strong>Global Illumination</strong>:</p><p>So far we&#8217;ve talked about direct light - Global Illumination is indirect lighting. When a light is in the scene it doesn&#8217;t just light from one angle, the light bounces around the scene and lights everything. We used to handle that using baked lighting, in which the CPU would handle it and that information would be stored.</p><p>Raytrace Global Illumination, by contrast, bounces the light after it hits an object, creating those secondary reflections. It can inherit the color of the object it touches. There are two raytraycing methods: Brute Force (more accurate) and Final Gather (less expensive)</p><p>In pre-rendered environments, this method also opens us up to lighting a scene using an HRDI image projected to a spherical map as a lightsource.</p>]]></content:encoded></item><item><title><![CDATA[Bringing a Marvelous Designer Cloth Simulation into Unreal]]></title><description><![CDATA[Project - Migrated from Tumblr]]></description><link>https://artofmaking.substack.com/p/bringing-a-marvelous-designer-cloth</link><guid isPermaLink="false">https://artofmaking.substack.com/p/bringing-a-marvelous-designer-cloth</guid><dc:creator><![CDATA[Annie Drake]]></dc:creator><pubDate>Mon, 04 Mar 2024 16:28:04 GMT</pubDate><enclosure url="https://substackcdn.com/image/youtube/w_728,c_limit/e4mJ6uJQwn0" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>&lt;iframe width="560" height="315" src="</p><div id="youtube2-e4mJ6uJQwn0" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;e4mJ6uJQwn0&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/e4mJ6uJQwn0?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen&gt;&lt;/iframe&gt;</p><p>Method 1: Simulate in Marvelous Designer and import as Geometry Cache<br><br>Create your Animation in Maya</p><ol><li><p>First you will need a preview mesh with a head on it. You can get them <a href="https://drive.google.com/drive/folders/1SNLa38CeMLmYq8KLQn67f6xFxM_7zkpa">here</a>, or you can export using quixel bridge and reexport. If you get your preview from that link, make sure it is the same body type as the metahuman you&#8217;re using. In the import settings for skeleton select &#8220;metahuman_base_skeleton&#8221;</p></li><li><p>Grab your body animation. Thats a longer tutorial, but make sure the animation starts on an A or T pose. I grabbed mine from rokoko studio, and applied an IK Rig and IK Regtargeter in Unreal.</p></li></ol><p>Unreal - make sure your body deforms correctly</p><ol><li><p>Enable the Metahuman plugin</p></li><li><p>Content &gt; Metahumans &gt; Common &gt; Common &gt; Open the metahuman preview mesh that corresponds with your body type</p></li><li><p><a href="https://drive.google.com/drive/folders/1SNLa38CeMLmYq8KLQn67f6xFxM_7zkpa">This folder</a> contains all preview meshes with heads, download the one that matches your body. Import, selecting &#8220;metahuman_base&#8221; for your skeleton.</p></li><li><p>Open that blueprint. In the &#8220;asset details&#8221; tab, find &#8220;Skeletal Mesh &gt; Post Process Animation Blueprint&#8221;, and load the character that matches your body type. Save.</p></li><li><p>Open your animation blueprint and set your preview mesh to be the preview mesh you just made. You&#8217;re looking for a green warning telling you that the post process animation blueprint is running. Apply to asset.</p></li><li><p>Export Asset (Top) &gt; Preview Mesh. Make sure export preview mesh is true.</p></li><li><p>If any body type comes too close to the cloth in a way you don&#8217;t want simulated, you can delete it in Maya and reexport before importing into Marvelous Designer.</p></li></ol><p>In Marvelous Designer</p><ol><li><p>File &gt; Import &gt; FBX, and apply the following settings: Scale - CM Daz. Joint and Cache Animation: True. Adjust the bounding box so it fits around your characters A or T Pose.</p></li><li><p>I grabbed the pattern for the Tamarind Dress from  <a href="https://www.moodfabrics.com/">https://www.moodfabrics.com/</a></p></li><li><p> and imported it as a pattern reference. (Right Click in 2D Window &gt; Add Background Image). I found that when doing the simulation, deleting any body parts not driving any motion yielded better results. Go into the animation tab, set simulation quality animation to stable. You&#8217;ll need to change the time warp to 2 if you&#8217;re exporting at 60 FPS. File &gt; Export &gt; Alembic</p></li></ol><p>In Unreal</p><ol><li><p>Import into Unreal. Make sure you&#8217;re on Geometric Cache, and set orientation to 3DSMax.</p></li><li><p>Animate. Drag your outfit into the level sequencer. Track &gt; Geometry Cache. You can crop the start and end position by right clicking the track in the LS and editing the properties. Move the clothing on top of your animated character. (Shift+RMB, Shift+LMB to copy paste values quickly)</p></li></ol>]]></content:encoded></item><item><title><![CDATA[Unreal Editor Updates]]></title><description><![CDATA[Notes - Dec 29, 2023 Migrated from Tumblr]]></description><link>https://artofmaking.substack.com/p/unreal-editor-updates</link><guid isPermaLink="false">https://artofmaking.substack.com/p/unreal-editor-updates</guid><dc:creator><![CDATA[Annie Drake]]></dc:creator><pubDate>Mon, 04 Mar 2024 16:26:25 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!BhPU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F384e7f1e-e08b-4113-a6c2-86f9a98f4fe5_144x144.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Small post, but some ease of life things that are new to Unreal</p><p>Make Navigation feel sane (like all other CG programs we&#8217;re used to)</p><p>Editor &gt; Editor Preferences</p><p>Search: Invert</p><ul><li><p>Invert Middle Mouse Pan - TRUE</p></li></ul><p>Search: Rotate</p><ul><li><p>Enable Archball Rotate - TRUE</p></li><li><p>Enable Screen Rotate - TRUE</p></li></ul><p>New Animation Hotkey Options:</p><p>Search: Viewport</p><ul><li><p>Jump to end - END</p></li><li><p>Jump to start - HOME</p></li><li><p>Scrub Time (with mouse) - B</p></li><li><p>Step Backwards - X</p></li><li><p>Step Forward - C</p></li><li><p>Step to Next Key - V</p></li><li><p>Step to Previous Key - Z</p></li><li><p>Toggle Play - Spacebar</p></li></ul>]]></content:encoded></item><item><title><![CDATA[Unreal 5.3.2 and Metahumans]]></title><description><![CDATA[Process Notes - Dec 29 2023 - Migrated from Tumblr]]></description><link>https://artofmaking.substack.com/p/unreal-532-and-metahumans</link><guid isPermaLink="false">https://artofmaking.substack.com/p/unreal-532-and-metahumans</guid><dc:creator><![CDATA[Annie Drake]]></dc:creator><pubDate>Mon, 04 Mar 2024 16:25:42 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!BhPU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F384e7f1e-e08b-4113-a6c2-86f9a98f4fe5_144x144.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This is the process notes to get a metahuman animating with facial and body animation, and rendering into the level sequence.</p><h2>Create and import your metahuman:</h2><ol><li><p>Create metahuman character with <a href="https://metahuman.unrealengine.com/">MetaHuman Creator (unrealengine.com)</a></p></li><li><p>In Unreal &gt; Window &gt; Quixel Bridge</p></li><li><p>Sign in and hit the down arrow in the upper right hand corner of your avatar picture to download.</p></li></ol><h2>Applying Facial Animation</h2><ol><li><p>In Unreal Launcher go to Marketplace and get/install Metahuman Plugin</p></li><li><p>If you have a good computer, go to Edit &gt; Project Settings &gt; Plugins | IMG Media &gt; Search caching, use global cache, and at least 2+ GB of system memory</p></li><li><p>Make sure the metahuman plugin is enabled</p></li><li><p>Make a new folder under content in the Content Drawer, if you right click you should now see Metahuman Animator as a type.</p></li><li><p>We will use the Capture Source to import footage recorded on Iphone, Metahuman Identity to calibrate a new metahuman face based on the actor. This is only done once per actor.</p></li><li><p>Metahuman Performance is used to process the actual take.</p></li><li><p>Create a capture source, and double click to edit blueprint. Here are 2 connection methods:</p></li><li><p>To connect to Iphone: Choose LiveLink Face Connection. Make sure computer and iphone are on the same network. In live link app, choose settings gear. Choose OSC Server, and copy the IP Address into the Device Address in Unreal. Save</p></li><li><p>To Source your captures from a local directory where you&#8217;ve saved the data: Choose Live Link Face Archives, and set the directory to the root of where your saves are. Save.</p></li><li><p>Tools &gt; Capture Manager, if you can see your takes, you were successful.</p></li><li><p>Select the takes you want, add to the queue, and import now.</p></li><li><p>Calibration: In the content drawer, right click &gt; Metahuman Animator &gt; Metahuman Identity. Create component &gt; From footage, and choose your calibration take</p></li><li><p>Scrub the timeline till you are at a front view, and click plus to add. Click the camera button to unlock, and repeat for left and right. Now click Metahuman Identity Solve. Select body, body type, then Mesh to Metahuman &gt; Auto Rig Metahuman Identity (Skeletal Mesh + Full Metahuman)</p></li><li><p>Add teeth by clicking Poses, Add Pose &gt; Add Teeth. Scrub the timeline to where your teeth are showing, and the upper and lower teeth are not overlapping, and promote the frame. Click Fit Teeth, and then Prepare for performance.</p></li><li><p>Process the Main Animation: Right Click in Content Drawer &gt; Metahuman Animator &gt; Metahuman Performance, Double click to enter blueprint. Top Right : Footage Capture Data &gt; Select your main take. For Metahuman Identity, choose your calibration take. Scroll Down, Identity &gt; Head Movement Mode &gt; Choose Control Rig. Process to solve. Export Level Sequence (top), Create, using default values.</p></li><li><p>Switch Calibrated metahuman head to match main metahuman: Click the calibrated metahuman head. To the right, with all selected, navigate to Animation &gt; Mesh, and switch the Skeletal Mesh Asset to the metahuman head you wish to import to.</p></li><li><p>Add your metahuman character you want to port to to the scene and add him or her to the sequencer. In sequencer, Track &gt; Actor to Sequencer &gt; Add &#8220;name&#8221;</p></li><li><p>In sequencer: Right click the layer containing your original metahuman head, and bake animation sequence to the MHA folder. Name it in a way that you can identify it as a character line later.</p></li><li><p>The new metahuman will now be loaded in the sequencer. (right) On the face subgroup, hit plus to track, Animation &gt; and select your baked animation. If the facial animation is not playing you have to delete the control rig.</p></li><li><p>Adding Body Animations: Open Content Drawer, and with MHA folder selected, Add &gt; Add Feature. Third Person Mode, add to project. This imports the Characters folder, which includes default animations that come with the third person character pack.</p></li><li><p>Retarget these animations to the metahuman skeleton: Content Drawer: Characters &gt; Mannequins &gt; Animations &gt; Manny. Select all animations, Right Click &gt; Retarget Animation Assets &gt; Duplicate &#8230;. At the top of the IK Retargeter, choose RTG_Mannequin. Set Source to SKM_Manny, and go with basic metahuman body for target. (f_med_nrw_body), Retarget.</p></li><li><p>Back in sequencer, next to your metahuman&#8217;s body click track and add one of the motion capture animations. We now have an animated body and head, but they are moving independently. If body animation is not showing in timeline, just restart engine.</p></li><li><p>Connect head and body: In sequencer select Body. In right side, under Animation, set a keyframe on Animation mode (with dropdown set to Use Custom Mode), and turn on &#8220;Disable post process blueprint&#8221;. If it doesn&#8217;t work try saving and restarting.</p></li><li><p>Allow face to control neck movement: Click on face tab in sequencer. Animation &gt; Anim Class &gt; Click folder. Find faceAnim_BP and double click to open blueprint. (Left) Animation Graphs &gt; AnimGraph &gt; Doubleclick to frame. Find &#8220;Layered Blend per Bone&#8221; Click on it, and in inspector change Blend Mode to Blend Mask.</p></li><li><p>Define your anim mask: Top click the skeleton button, then in outline, Settings &gt; Blend Profiles &gt; Add Blend Mask. Rename it. In search bar, look for &#8220;head&#8221;. Drag the value to 1 and save. Go back to the &#8220;face Anim BP&#8221; tab, and in the layered blend per bone, change Blend Mode to &#8220;blend mask&#8221;, expand blend masks rollout, and select your blendmask. Compile and close.</p></li></ol><h2>Retarget Mocap</h2><ol><li><p>Import your motion capture</p></li><li><p>Right Click: Animation &gt; Retargeting &gt; IK Rig. Drag in your skeletal Mesh for your mocap, and then create a new IK Rig node for your metahuman body.</p></li><li><p>Create Chains: Right click your root node, and select Set Retarget Root. Select all spine bones, right click &gt; New Retarget Chain. Do this for Spine, Neck, Head, Right Arm, Left Arm, Right Leg, and Left Leg. Do this again for your other IK group (if you did your mocap do your metahuman definition), making sure that the names and order match your last profile.</p></li><li><p>Content Browser: Right Click &gt; Animation &gt; Retargeting &gt; IK Retargeter. Drag your IK Definitions into your source (Mocap) and target (Metahuman) fields. Move the bones on the metahuman so that it matches the TPose of the mocap as closely as possible, and then hit Create &gt; Export Pose Asset.</p></li><li><p>Switch from Edit Retarget to Run Retargeter, and in the (bottom right) asset browser, double click your animation. It should play on both skeletons.</p></li><li><p>At the top of the asset browser, select Export Selected Animations.</p></li></ol><h2>Modify Body Animation</h2><ol><li><p>Create a new Level Sequence</p></li><li><p>Drag in your camera, character, and any props you want to animate</p></li><li><p>Under the body tab, Delete the Metahuman Control Rig for now</p></li><li><p>Next to body hit Track &gt; Animation, and find the new retargeted motion capture you just created. You can drag in multiple animations, and blend them together as you would in Maya&#8217;s Time Editor.</p></li><li><p>When you&#8217;re happy with the blend, right click body &gt; Bake to Control Rig : Choose your metahuman rig</p></li><li><p>Click + to create an additive layer</p></li><li><p>Turn on auto Keyframe (top Diamond with key inside)</p></li><li><p>The Animation Tab (window) becomes available if you are in the Animation Mode (Like Maya, top left). Under the Animation tab: Unreal added &#8220;constraints&#8221;, which can be animated on and off, and animated on top of. They also have pivot, which you can animate.</p></li><li><p>In level sequence, under &#8220;eyeball&#8221;, you can click &#8220;Auto Expand Nodes on Selection&#8221;, if you&#8217;re animating in the LS this can get annoying. (But auto keyframe won&#8217;t work unless you set your first keyframe). The Grid with the squiggle gives you your curve editor.</p></li></ol><h2>Rendering</h2><p>Add Post Process Volume</p><ul><li><p>You can add things here like Bloom or Exposure if you want to add post effects to your render</p></li><li><p>You can bump up the raytracing values to 32 to get a better render (in theory, but I didn&#8217;t see that it made a huge difference) by searching &#8220;sample&#8221;</p></li></ul><p>Level Sequence</p><ul><li><p>Hit the Movie Icon to pull up render settings</p></li><li><p>Make note of where your output is and change if need be</p></li><li><p>All sources suggest adding anti-aliasing. I&#8217;ve heard 4 and 4 are good settings, I&#8217;ve also heard 1 and 32. Turn on &#8220;Override Anti Aliasing&#8221;</p></li><li><p>Render Local</p></li></ul>]]></content:encoded></item><item><title><![CDATA[Tell Me]]></title><description><![CDATA[Design Research - Sometime 2015 Migrated from Tumblr]]></description><link>https://artofmaking.substack.com/p/tell-me</link><guid isPermaLink="false">https://artofmaking.substack.com/p/tell-me</guid><dc:creator><![CDATA[Annie Drake]]></dc:creator><pubDate>Mon, 04 Mar 2024 16:23:24 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!BhPU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F384e7f1e-e08b-4113-a6c2-86f9a98f4fe5_144x144.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When I was looking for potential startup ideas, this is one I invested some time into - it was essentially the idea of embedding a camera, screen and internet connected device into a children&#8217;s toy, so that the toy could &#8220;look&#8221; at objects in the world, recognize what they were, and slowly walk the child through language learning via that interface.</p><p>The idea was based on the premise that children&#8217;s minds are more plastic in regards to language, but a lot of places which do not border another country don&#8217;t have the access to foreign languages that many in Europe enjoy.</p><p>In the end, I did not pursue it, but in retrospect I think that was a mistake - this could have been seriously cool!  Publishing my research notes.</p><p></p><h2>Design notes for a playful method of learning language, using image recognition on a camera - tied into children&#8217;s toys.</h2><h2><strong><a href="https://t.umblr.com/redirect?z=https%3A%2F%2Fcloud.google.com%2Ftranslate%2Fdocs&amp;t=MmQ0YTFhZTRhMmU0ODM5OTdiNDQ1MjEzNjdkZTZkZGYxN2MxNWRkOCxjUTA1cDhVcA%3D%3D&amp;b=t%3AJzrcZpU2TvEuTozazUZLEw&amp;p=https%3A%2F%2Fartofmaking.tumblr.com%2Fpost%2F736955711411683328%2Ftellme&amp;m=1&amp;ts=1709568998">Google Translate API</a></strong></h2><p>- Content of page under&nbsp;<a href="http://creativecommons.org/licenses/by/3.0/">Creative Commons Attribution 3.0 Liense</a>&nbsp;(Share and Adapt allowed, even for commercial purposes, as long as credit is given)<br>- Code under <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache 2.0 License</a></p><h2><strong>Bing API</strong></h2><p>Only offers for windows 8, web and windows phone. &nbsp;Hm. &nbsp;Not sure about that, it sounded like Eric really favored the Linex / Mac operating system for computer vision. &nbsp;Ask the guys about that.</p><h2><strong>Image Recognition APIS</strong></h2><p><a href="http://blog.mashape.com/list-of-14-image-recognition-apis/">List of 14 Image Recognition APIS</a></p><p><a href="http://gizmodo.com/googles-image-recognition-software-can-now-describe-ent-1660033808">Gizmodo Article on Google&#8217;s Image Recognition API</a></p><p><a href="https://t.umblr.com/redirect?z=https%3A%2F%2Fcloud.google.com%2Fprediction%2Fdocs%2Fgetting-started&amp;t=MzQ1YjNiN2FhNzA1YWUwNmI0NjAzMzBmZTYwYmNmNjRhOTdjNjRlNyxjUTA1cDhVcA%3D%3D&amp;b=t%3AJzrcZpU2TvEuTozazUZLEw&amp;p=https%3A%2F%2Fartofmaking.tumblr.com%2Fpost%2F736955711411683328%2Ftellme&amp;m=1&amp;ts=1709568998">Google&#8217;s prediction API</a></p><p><a href="https://www.recognize.im/site/howitworks">recognize.im</a></p><p><a href="https://6px.io/">6px</a></p><p><a href="https://www.mashape.com/vufind/recognize-1">Recognize</a></p><p><a href="https://www.mashape.com/imagesearcher/camfind">camfind</a></p><h2><strong>Learn from multiple people.</strong></h2><p>&#8220;When you are exposed to a lot of people you get a much better sense of what the sound of a word is supposed to be,&#8221; says Davidson. &#8220;You avoid exposing yourself to what could be idiosyncrasies in one individual&#8217;s speech patterns.&#8221;</p><h2><strong>Learn as much vocabulary as you can.</strong></h2><p>&#8220;Learning loads of vocabulary is really much more useful than learning grammar,&#8221; says Simcott. &#8220;Learning grammar is good too, but with a lot of vocabulary you can successfully describe anything you need to.&#8221;</p><h2><strong>Translate the Web</strong></h2><p><a href="http://lifehacker.com/most-popular-language-learning-tool-duolingo-1449947237">Duolingo</a>&nbsp;places the skill level of the user and has them translate from another language. &nbsp;Other users can correct if they&#8217;re wrong. &nbsp;The cool thing about this is that it incentives deep learning by forcing the user to solve problems</p><p><a href="http://ankisrs.net/">Aniki</a>&nbsp;is a flash card memorization program, which reminds me of Nolan&#8217;s company</p><h2><strong>What are the most common words and phrases? &nbsp;Can we focus on those first somehow?</strong></h2><p><a href="https://t.umblr.com/redirect?z=http%3A%2F%2Fwww.pimsleur.com%2F&amp;t=YTgyZmYwOTg0Zjc5ZmY1MjI5NGM0NTA4MjFkMzhiY2Y0MjZhZjc5NyxjUTA1cDhVcA%3D%3D&amp;b=t%3AJzrcZpU2TvEuTozazUZLEw&amp;p=https%3A%2F%2Fartofmaking.tumblr.com%2Fpost%2F736955711411683328%2Ftellme&amp;m=1&amp;ts=1709568998">Pimsleur method</a> is an audio based program which focuses on the basic building blocks of the language</p><p>the cool thing about this is that you&#8217;re setting a story in english, and then saying the dialogue in spanish. &nbsp;Good use of imagination and memory castles</p><p>Has you repeat parts of the word backwards and imitate accents. &nbsp;Repeats the parts of the words individually, then strings them together&nbsp;</p><p>Make sounds at each other? &nbsp;Gabe constantly skats because a video game character does it</p><p>change the word order of what youre having them repeat in more and more complex patterns. &nbsp;Excuse me, sinorita. &nbsp;Excuse me, pardon. &nbsp;Excuse me.</p><p><a href="http://linguistlist.org/ask-ling/lang-acq.cfm">How do children acquire language?</a></p><h2><strong>Media (consumption vs playing together)</strong></h2><p>- Card games using learned words. &nbsp;Competing game hook is seeing who has collected more words, and then having those words show up enough times that it is practiced</p><p>- Karaoke songs. &nbsp;Automatically increase required pronunciation based on learned skill at pronunciation. &nbsp;Offer new words at the beginning of song that user might not know</p><p>- Hand puppet plays, dictation and mood setting while letting the child handle dialogue however they feel</p><h2><strong>Crossing Patterns</strong></h2><p>But suppose now one child in the group replies &#8216;moo&#8217; to your question. Before you start worrying about this child&#8217;s linguistic (or cognitive) abilities, try to think about your question and the child&#8217;s answer on the child&#8217;s own terms, not yours. You are expecting a word that sounds like 'banana&#8217;, but how does the child know that? And how do you know what prompted the child to give you this answer? In particular, why should the sound of the word be more relevant to the child than, say, the shape of the object you&#8217;re holding? It may well be that this child has recently been fascinated by the night sky, and all shiny things in it whose names he&#8217;s just learned. And a banana does look like a waning or waxing moon. This child is also generalising, though in a different way from his friends. He is besides showing you that he knows how to relate what he learned before to whatever activity is required of him now, which is a very good thing to have mastered indeed. (On a side note, it is this kind of generalization that makes young children, sometimes very embarrassingly, call all adult males 'daddy&#8217;.)</p><h2><strong>Books</strong></h2><ul><li><p>David Crystal&#8217;s book <em>Listen to your Child: A Parent&#8217;s Guide to Children&#8217;s Language</em> (Penguin, 1989) offers a very accessible and very entertaining account of what children do with their own language learning.</p></li><li><p>Eve Clark&#8217;s book <em>First Language Acquisition</em> (Cambridge University Press, 2003) is a comprehensive &#8211; and more technical &#8211; account of child language development.</p></li></ul><h2><strong>Thoughts</strong></h2><p>setup expectation for play, so that people don&#8217;t find &#8220;looking ridiculous&#8221; to be a barrier.</p><p>A Thesaurus tie in might be helpful</p><h2><strong>Random APIS</strong></h2><p><a href="https://www.mashape.com/ar7hur/nlp-and-voice-interface-for-apps-wit-ai/overview">Natural language processing</a></p><p><a href="https://www.mashape.com/aylien/text-analysis">Natural Language Processing 2</a></p><p><a href="https://www.mashape.com/pannous/jeannie">smart responses to natural language questions</a></p><p><a href="https://www.mashape.com/mnutsch/sentence-recognition">Sentence Recognition<br></a></p><p><a href="https://www.mashape.com/montanaflynn/text-to-speech">text to speech Really good!</a></p><p><a href="https://www.mashape.com/imagesearcher/camfind">camfind- image recognition</a></p><p><a href="https://www.mashape.com/webknox/question-answering">question answering</a></p>]]></content:encoded></item><item><title><![CDATA[Stained Glass Window in Unreal]]></title><description><![CDATA[Project - Sep 10, 2015 Migrated from Tumblr]]></description><link>https://artofmaking.substack.com/p/stained-glass-window-in-unreal</link><guid isPermaLink="false">https://artofmaking.substack.com/p/stained-glass-window-in-unreal</guid><dc:creator><![CDATA[Annie Drake]]></dc:creator><pubDate>Mon, 04 Mar 2024 13:55:42 GMT</pubDate><enclosure url="https://substackcdn.com/image/youtube/w_728,c_limit/utIAn9ok-YI" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>One day, our manager Ravjiv walked in like Santa Clause with a couple full body transparent touch monitors.  We never got a project to do anything with them, so with some downtime I decided to make an interactive stained glass window, which a depth enabled interface.</p><p>Sadly I never completed this project and don&#8217;t have a video of it playing on the monitor, the background was just an Unreal ocean - in the intended final product you would just see through it to the world.</p><p>&lt;iframe width="560" height="315" src="</p><div id="youtube2-utIAn9ok-YI" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;utIAn9ok-YI&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/utIAn9ok-YI?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen&gt;&lt;/iframe&gt;</p><p>Rachel designed a variety of beautiful window patterns, cut them all apart in 3d Max, and did the fine detail sculpting on the foam.  Seth integrated the Perceptual SDK&#8217;s finger tracking into Unreal, and connected it to a <a href="https://www.adafruit.com/products/1689">fadecandy </a>to drive the lights.</p><p>I built the physical skeleton, and the Unreal Components. &nbsp;Here&#8217;s a breakdown:</p><h2>Skeleton</h2><p>The first thing I did was weld a stand, which could hold the television. &nbsp;I did it with a MIG welder, and steel.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Nih3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F994e8ab6-3407-49be-89d1-ee238994c252_500x373.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Nih3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F994e8ab6-3407-49be-89d1-ee238994c252_500x373.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Nih3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F994e8ab6-3407-49be-89d1-ee238994c252_500x373.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Nih3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F994e8ab6-3407-49be-89d1-ee238994c252_500x373.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Nih3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F994e8ab6-3407-49be-89d1-ee238994c252_500x373.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Nih3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F994e8ab6-3407-49be-89d1-ee238994c252_500x373.jpeg" width="500" height="373" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/994e8ab6-3407-49be-89d1-ee238994c252_500x373.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:373,&quot;width&quot;:500,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="image" title="image" srcset="https://substackcdn.com/image/fetch/$s_!Nih3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F994e8ab6-3407-49be-89d1-ee238994c252_500x373.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Nih3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F994e8ab6-3407-49be-89d1-ee238994c252_500x373.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Nih3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F994e8ab6-3407-49be-89d1-ee238994c252_500x373.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Nih3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F994e8ab6-3407-49be-89d1-ee238994c252_500x373.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>I got eyeballed it (like making a sewing pattern) and it came off slightly angled, though the TV fit in snugly when I took some of its frame off.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wXET!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F017e7605-80d4-4596-bdf4-429ce11ef7d1_500x669.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wXET!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F017e7605-80d4-4596-bdf4-429ce11ef7d1_500x669.jpeg 424w, https://substackcdn.com/image/fetch/$s_!wXET!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F017e7605-80d4-4596-bdf4-429ce11ef7d1_500x669.jpeg 848w, https://substackcdn.com/image/fetch/$s_!wXET!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F017e7605-80d4-4596-bdf4-429ce11ef7d1_500x669.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!wXET!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F017e7605-80d4-4596-bdf4-429ce11ef7d1_500x669.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wXET!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F017e7605-80d4-4596-bdf4-429ce11ef7d1_500x669.jpeg" width="500" height="669" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/017e7605-80d4-4596-bdf4-429ce11ef7d1_500x669.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:669,&quot;width&quot;:500,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="image" title="image" srcset="https://substackcdn.com/image/fetch/$s_!wXET!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F017e7605-80d4-4596-bdf4-429ce11ef7d1_500x669.jpeg 424w, https://substackcdn.com/image/fetch/$s_!wXET!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F017e7605-80d4-4596-bdf4-429ce11ef7d1_500x669.jpeg 848w, https://substackcdn.com/image/fetch/$s_!wXET!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F017e7605-80d4-4596-bdf4-429ce11ef7d1_500x669.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!wXET!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F017e7605-80d4-4596-bdf4-429ce11ef7d1_500x669.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>My plan was to build a <a href="https://t.umblr.com/redirect?z=http%3A%2F%2Fwww.homedepot.com%2Fp%2FOwens-Corning-FOAMULAR-150-1-in-x-4-ft-x-8-ft-R-5-Tongue-and-Groove-Insulation-Sheathing-68WD%2F100320355%3FMERCH%3DREC-_-NavPLPHorizontal1_rr-_-NA-_-100320355-_-N&amp;t=YzBkZTYyZGFjMDQwNDIzNGMxMjQ2ZTlmNTMzNzU3YWNkYjE0NTkzYSw2Z2hwTmF2WA%3D%3D&amp;b=t%3AJzrcZpU2TvEuTozazUZLEw&amp;p=https%3A%2F%2Fartofmaking.tumblr.com%2Fpost%2F736955669254651904%2Fstained-glass-window&amp;m=1&amp;ts=1709559230">polystyrene</a> frame (a sculpt-able foam insulation you can get at Home Depot, Home Depot Pro if you want it in 2&#8243; x 4&#8242; x 8&#8242; sheets like I did). &nbsp;But in order for it to fit, it had to compensate for that strange angle my weld made. &nbsp;In the future when welding strait angles, I plan on making a frame to hold my metal in at the correct angle!!!</p><p>To get it right, I ended up hanging a needle off thread from different points, and then measuring their XY distance from center bottom. &nbsp;The rest of the measurements (length and width of metal cuts) were really straightforward. &nbsp;I was worried it won&#8217;t work, but to my surprise, my foam mold came out really accurately.&nbsp;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rzXk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e121f22-99ac-4aa4-aa77-283bbbac44ce_500x456.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rzXk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e121f22-99ac-4aa4-aa77-283bbbac44ce_500x456.jpeg 424w, https://substackcdn.com/image/fetch/$s_!rzXk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e121f22-99ac-4aa4-aa77-283bbbac44ce_500x456.jpeg 848w, https://substackcdn.com/image/fetch/$s_!rzXk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e121f22-99ac-4aa4-aa77-283bbbac44ce_500x456.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!rzXk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e121f22-99ac-4aa4-aa77-283bbbac44ce_500x456.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rzXk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e121f22-99ac-4aa4-aa77-283bbbac44ce_500x456.jpeg" width="500" height="456" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5e121f22-99ac-4aa4-aa77-283bbbac44ce_500x456.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:456,&quot;width&quot;:500,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="image" title="image" srcset="https://substackcdn.com/image/fetch/$s_!rzXk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e121f22-99ac-4aa4-aa77-283bbbac44ce_500x456.jpeg 424w, https://substackcdn.com/image/fetch/$s_!rzXk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e121f22-99ac-4aa4-aa77-283bbbac44ce_500x456.jpeg 848w, https://substackcdn.com/image/fetch/$s_!rzXk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e121f22-99ac-4aa4-aa77-283bbbac44ce_500x456.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!rzXk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e121f22-99ac-4aa4-aa77-283bbbac44ce_500x456.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>With that, I made a 3d file for what I wanted my exterior wall to look like, and made it hollow around where I thought the internal skeleton would be.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jsJN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3b17661-993f-4a8d-8aba-369fbcdf425c_500x456.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jsJN!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3b17661-993f-4a8d-8aba-369fbcdf425c_500x456.jpeg 424w, https://substackcdn.com/image/fetch/$s_!jsJN!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3b17661-993f-4a8d-8aba-369fbcdf425c_500x456.jpeg 848w, https://substackcdn.com/image/fetch/$s_!jsJN!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3b17661-993f-4a8d-8aba-369fbcdf425c_500x456.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!jsJN!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3b17661-993f-4a8d-8aba-369fbcdf425c_500x456.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jsJN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3b17661-993f-4a8d-8aba-369fbcdf425c_500x456.jpeg" width="500" height="456" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b3b17661-993f-4a8d-8aba-369fbcdf425c_500x456.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:456,&quot;width&quot;:500,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="image" title="image" srcset="https://substackcdn.com/image/fetch/$s_!jsJN!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3b17661-993f-4a8d-8aba-369fbcdf425c_500x456.jpeg 424w, https://substackcdn.com/image/fetch/$s_!jsJN!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3b17661-993f-4a8d-8aba-369fbcdf425c_500x456.jpeg 848w, https://substackcdn.com/image/fetch/$s_!jsJN!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3b17661-993f-4a8d-8aba-369fbcdf425c_500x456.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!jsJN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3b17661-993f-4a8d-8aba-369fbcdf425c_500x456.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>I broke it into 2&#8243; thick 3d files and then fed that into the ShopBot Alpha at <a href="http://www.techshop.ws/">TechShop</a>. &nbsp;I exported my slices to .STL, and then fed them into Cut3d, which was a strange program to get used to, but worked fine once I figured it out.&nbsp;</p><p>Then it was just a waiting game, which I used to knit. &nbsp;It took about 2 hours per print, of which I had 7. &nbsp;Slice 6 had to be cut on both the front and back which made it 16 hours. &nbsp;I knocked it all out in one night, because I only had one shot at borrowing a truck.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!vh7F!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e97ea54-893a-488e-baae-ae07c527161c_500x500.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!vh7F!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e97ea54-893a-488e-baae-ae07c527161c_500x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!vh7F!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e97ea54-893a-488e-baae-ae07c527161c_500x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!vh7F!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e97ea54-893a-488e-baae-ae07c527161c_500x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!vh7F!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e97ea54-893a-488e-baae-ae07c527161c_500x500.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!vh7F!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e97ea54-893a-488e-baae-ae07c527161c_500x500.jpeg" width="500" height="500" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8e97ea54-893a-488e-baae-ae07c527161c_500x500.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:500,&quot;width&quot;:500,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="image" title="image" srcset="https://substackcdn.com/image/fetch/$s_!vh7F!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e97ea54-893a-488e-baae-ae07c527161c_500x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!vh7F!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e97ea54-893a-488e-baae-ae07c527161c_500x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!vh7F!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e97ea54-893a-488e-baae-ae07c527161c_500x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!vh7F!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e97ea54-893a-488e-baae-ae07c527161c_500x500.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>I realized last minute that I needed arrows to move from one scene to the other, so I just cut them out by hand with an exacto blade. &nbsp;You can get nice sculpting results with a <a href="https://t.umblr.com/redirect?z=http%3A%2F%2Fwww.amazon.com%2Fgp%2Fproduct%2FB00002X1ZH%2Fref%3Dpd_lpo_sbs_dp_ss_2%3Fpf_rd_p%3D1944687662%26pf_rd_s%3Dlpo-top-stripe-1%26pf_rd_t%3D201%26pf_rd_i%3DB00002X1ZP%26pf_rd_m%3DATVPDKIKX0DER%26pf_rd_r%3D0QTR01CM5QH6V907QFAZ&amp;t=MmQzOWI1YmE5MWU2NDYzMWZiNzUzYzYyYWJjYjQ3NDU0NzIwYmE1Niw2Z2hwTmF2WA%3D%3D&amp;b=t%3AJzrcZpU2TvEuTozazUZLEw&amp;p=https%3A%2F%2Fartofmaking.tumblr.com%2Fpost%2F736955669254651904%2Fstained-glass-window&amp;m=1&amp;ts=1709559230">Stanley Surfoam Shaver</a>&nbsp;and sandpaper.</p><p>lights</p><h2>Unreal</h2><p>I downloaded this <a href="https://github.com/UE4-OceanProject/OceanProject">beautiful ocean scene</a> and used that as my background, deleting all the extras.</p><p>I won&#8217;t go over all the details of putting it together, you can <a href="https://github.com/AnnieCat/StainedGlass">download it and look it over in Github</a>. &nbsp;Note- its big and unedited for human consumption!</p><p>Here are some interesting things I discovered along the way:</p><ul><li><p>You can&#8217;t make a public array of mesh components. &nbsp;You can add them into the array at the construction script using&nbsp;&#8220;make array&#8221;, and then promote that to a variable. &nbsp;I used that to create a changeable script on the buttons.</p></li><li><p>You can promote a series of calls to a function, when things are starting to repeat for cleaner &#8220;code&#8221;</p></li><li><p>If you need to fake a mouseover without using the actual mouse (in my case I was planning on replacing mouseover with an event generated by the depth camera) you can use&nbsp;&#8220;line trace component&#8221;. &nbsp;It acts like a raytrace. &nbsp;Give it the starting point of&nbsp;&#8220;World Location&#8221;. &nbsp;For &#8220;Trace End&#8221;, multiply&nbsp;&#8220;World Direction&#8221; with some large number (I used 10,000), and add it&#8217;s output to World Location, and feed that into&nbsp;&#8220;Trace End&#8221;</p></li><li><p>Creating a state machine to handle individual mesh components using &#8220;Add Timeline&#8221;, even when using unique Timelines, gets REALLY difficult. &nbsp;I gave up and just made each of the GUI items their own separate object. &nbsp;(Though <em>Switch on Int</em>&nbsp;was really helpful, if you have an active index)</p></li><li><p>It seems better to Create Dynamic Material Instances in Blueprint, rather than actually making them as part of your local assets. &nbsp;That way unreal gets rid of them when you&#8217;re done- and takes care of the memory management for you.</p></li></ul>]]></content:encoded></item><item><title><![CDATA[Photogrammetry Porting Pipeline for VR]]></title><description><![CDATA[Pipeline - Dec 10, 2023 Migrated from Tumblr]]></description><link>https://artofmaking.substack.com/p/photogrammetry-porting-pipeline-for</link><guid isPermaLink="false">https://artofmaking.substack.com/p/photogrammetry-porting-pipeline-for</guid><dc:creator><![CDATA[Annie Drake]]></dc:creator><pubDate>Mon, 04 Mar 2024 13:46:50 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Y3Hj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b226a04-7182-48dd-ab54-303dfb3b00e3_500x499.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This is an old pipeline I wrote for a job many years ago - when photogrammetry was around but the libraries were not fleshed out, and the advancements made by Metahuman and Reallusion were not available. In addition to that, I was limited by a razor thin development budget. Here&#8217;s what I came up with:</p><h2>Generate a Photogrammetry Mesh</h2><p>Start with a Mixamo character - this spits out a rigged model already skinned, which plugs directly into Lip Sync Pro.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Y3Hj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b226a04-7182-48dd-ab54-303dfb3b00e3_500x499.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Y3Hj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b226a04-7182-48dd-ab54-303dfb3b00e3_500x499.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Y3Hj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b226a04-7182-48dd-ab54-303dfb3b00e3_500x499.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Y3Hj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b226a04-7182-48dd-ab54-303dfb3b00e3_500x499.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Y3Hj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b226a04-7182-48dd-ab54-303dfb3b00e3_500x499.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Y3Hj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b226a04-7182-48dd-ab54-303dfb3b00e3_500x499.jpeg" width="364" height="363.272" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4b226a04-7182-48dd-ab54-303dfb3b00e3_500x499.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:499,&quot;width&quot;:500,&quot;resizeWidth&quot;:364,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="image" title="image" srcset="https://substackcdn.com/image/fetch/$s_!Y3Hj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b226a04-7182-48dd-ab54-303dfb3b00e3_500x499.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Y3Hj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b226a04-7182-48dd-ab54-303dfb3b00e3_500x499.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Y3Hj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b226a04-7182-48dd-ab54-303dfb3b00e3_500x499.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Y3Hj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b226a04-7182-48dd-ab54-303dfb3b00e3_500x499.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!vh2E!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F708c445c-2bf9-4a12-a56e-7cd43db0d972_500x291.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!vh2E!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F708c445c-2bf9-4a12-a56e-7cd43db0d972_500x291.jpeg 424w, https://substackcdn.com/image/fetch/$s_!vh2E!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F708c445c-2bf9-4a12-a56e-7cd43db0d972_500x291.jpeg 848w, https://substackcdn.com/image/fetch/$s_!vh2E!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F708c445c-2bf9-4a12-a56e-7cd43db0d972_500x291.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!vh2E!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F708c445c-2bf9-4a12-a56e-7cd43db0d972_500x291.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!vh2E!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F708c445c-2bf9-4a12-a56e-7cd43db0d972_500x291.jpeg" width="576" height="335.232" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/708c445c-2bf9-4a12-a56e-7cd43db0d972_500x291.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:291,&quot;width&quot;:500,&quot;resizeWidth&quot;:576,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="image" title="image" srcset="https://substackcdn.com/image/fetch/$s_!vh2E!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F708c445c-2bf9-4a12-a56e-7cd43db0d972_500x291.jpeg 424w, https://substackcdn.com/image/fetch/$s_!vh2E!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F708c445c-2bf9-4a12-a56e-7cd43db0d972_500x291.jpeg 848w, https://substackcdn.com/image/fetch/$s_!vh2E!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F708c445c-2bf9-4a12-a56e-7cd43db0d972_500x291.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!vh2E!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F708c445c-2bf9-4a12-a56e-7cd43db0d972_500x291.jpeg 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Using a photogrammetry scan, morph the geometry of the starter character, and port over the textures. To make this faster, I wrote a <a href="https://www.youtube.com/watch?v=MbjFJeUe-Yk">pymel script</a> for speeding up the process.</p><p>&lt;iframe width="560" height="315" src="</p><div id="youtube2-MbjFJeUe-Yk" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;MbjFJeUe-Yk&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/MbjFJeUe-Yk?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen&gt;&lt;/iframe&gt;</p><h2>Create Facial Capture</h2><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!M35H!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d6b9a26-6c81-4d87-b6c7-341d39824c70_500x140.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!M35H!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d6b9a26-6c81-4d87-b6c7-341d39824c70_500x140.jpeg 424w, https://substackcdn.com/image/fetch/$s_!M35H!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d6b9a26-6c81-4d87-b6c7-341d39824c70_500x140.jpeg 848w, https://substackcdn.com/image/fetch/$s_!M35H!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d6b9a26-6c81-4d87-b6c7-341d39824c70_500x140.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!M35H!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d6b9a26-6c81-4d87-b6c7-341d39824c70_500x140.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!M35H!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d6b9a26-6c81-4d87-b6c7-341d39824c70_500x140.jpeg" width="500" height="140" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8d6b9a26-6c81-4d87-b6c7-341d39824c70_500x140.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:140,&quot;width&quot;:500,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="image" title="image" srcset="https://substackcdn.com/image/fetch/$s_!M35H!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d6b9a26-6c81-4d87-b6c7-341d39824c70_500x140.jpeg 424w, https://substackcdn.com/image/fetch/$s_!M35H!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d6b9a26-6c81-4d87-b6c7-341d39824c70_500x140.jpeg 848w, https://substackcdn.com/image/fetch/$s_!M35H!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d6b9a26-6c81-4d87-b6c7-341d39824c70_500x140.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!M35H!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d6b9a26-6c81-4d87-b6c7-341d39824c70_500x140.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Autodesk Recap is what I was using for the model photogrammetry scan, and it worked great for the initial portrait. It did <em>not</em> work well for capturing blendshapes, however, due to how many photos it needs. It&#8217;s just impossible for a model to stay still that long.</p><p>For this I used a camera from a defunkt startup called <a href="https://www.fuel3d.com/">Fuel3D</a>. They were originally aiming to serve optometrists for virtual eyeglass fitting and do a very good job of a single photo capture by <a href="http://www.zarria.net/nrmphoto/nrmphoto.html">simulating this research method</a>. The camera itself combines 2 RGB cameras and three flashes, setting them all off in a quick succession - gathering two points of view lit at three different angles. The software then processes and generates a fairly high-resolution mesh which doesn&#8217;t take too long to capture.</p><p>Once blendshapes were created based on the Fuel3D capture, I rigged my model using IClone and exported it.</p><p>&lt;blockquote class="imgur-embed-pub" lang="en" data-id="a/Kesx9qr" data-context="false" &gt;&lt;a href="//imgur.com/a/Kesx9qr"&gt;&lt;/a&gt;&lt;/blockquote&gt;&lt;script async src="//s.imgur.com/min/embed.js" charset="utf-8"&gt;&lt;/script&gt;</p><h2>Create Deformation Blendshapes</h2><p>These characters were to be used in VR - where realistic hands are <em>very</em> important. Since my process was cheap photogrammetry and speed oriented (I did not have a license to Zbrush, or the computer/tablet to handle it), I created scans of muscles deforming at the angles I needed.</p><p>I then went into maya and rotated the model so it would be in the position which would trigger that deformation, lined up a reference scan, and then used this series of tools to create a blendshape for that rotational angle</p><p><a href="https://github.com/AnnieCat/CharacterTools/blob/master/captureMirroredState_2.py">CaptureMirroredState-2.py</a> and <a href="https://github.com/AnnieCat/CharacterTools/blob/master/MirrorVerts.py">MirrorVerts.py</a> are a two part series of pymel scripts which work together. CaptureMirroredState_2 scrolls through a list of selected vertices, finds its mirror vertex, and saves both to a file for later access. This is important, because if the vertex ID is altered, it can break the blendshape system. MirrorVerts copies the vertex positions in said saved group to one side or the other.</p><p><a href="https://github.com/AnnieCat/CharacterTools/blob/master/SnapToNearbyVerts.py">SnapToNearbyVerts.py</a> scrolls through a list of selected vertices and snaps to the nearest vertex, regardless of ID.</p><p><a href="https://github.com/AnnieCat/CharacterTools/blob/master/CopyVerts.py">CopyVerts.py</a> takes two models with the same set of vertex ID configurations and copies the position of each vertex from one to the other.</p><p><a href="https://github.com/AnnieCat/CharacterTools/blob/master/mirrorJoints.py">MirrorJoints.py</a> copies the rotation of joints from one side to the other.</p><p>I would then take note of the joint rotation values, skin the new deformed mesh to the skeleton (enabling multiple bind poses) and then reset the rotation of the skeleton. This became my new blendshape morph target.</p><p>Fingernails, caruncula, outer eye, and hair needed to be manually created using good ol&#8217; artistic elbow grease. I did leverage the hair in mixamo as much as possible to get around creating hair cards by hand.</p><h2>Interactive IK</h2><p>This character pipeline was meant to generate characters for both first and third person use in VR, which meant they had to work as NPCs and embodied VR characters in 6DOF.</p><p>In order to drive both control methods, I set them up using <a href="https://t.umblr.com/redirect?z=https%3A%2F%2Fassetstore.unity.com%2Fpackages%2Ftools%2Fanimation%2Ffinal-ik-14290&amp;t=ZTU1NzZkOWI0NjU1YjAzYTgyMTI4YzlhZDgxMTRlYTk5Yzc0NGNjMiw3QnVkWVZRcw%3D%3D&amp;b=t%3AJzrcZpU2TvEuTozazUZLEw&amp;p=https%3A%2F%2Fartofmaking.tumblr.com%2Fpost%2F736359664697180160%2Fphotogrammetry-porting-pipeline&amp;m=1&amp;ts=1709559230">Final IK</a>.</p><p>For the first-person setup I set it to VRIK with the following values:</p><ul><li><p>Under the spine, set the head target to the VR headset position, and set position and rotation weight to 1.</p></li><li><p>Load the left- and right-hand position to the handset positions.</p></li><li><p>Under Locomotion, set <strong>Foot Distance</strong> to 0.11, <strong>Step Threshold</strong> to 0.21, <strong>Root Speed</strong> to 32, and <strong>Step Speed</strong> to 3.75.</p></li></ul><p>For the third person (NPC) controls I used a biped IK, and had the look IK controller follow the speaker (in multi character scenarios), or the camera (in 1:1 scenarios)</p><h2>Animating the Hands</h2><p>Download <a href="https://github.com/AnnieCat/CharacterTools/blob/master/HandController.cs">HandController.cs</a>, and <a href="https://github.com/AnnieCat/CharacterTools/blob/master/handStates.fbx">HandStates.fbx</a> <a href="https://github.com/AnnieCat/CharacterTools/blob/master/HandStates.controller">HandStates.controller</a>, <a href="https://github.com/AnnieCat/CharacterTools/blob/master/LeftHand.mask">LeftHand.mask</a>, and <a href="https://github.com/AnnieCat/CharacterTools/blob/master/RightHand.mask">RightHand.mask</a>.</p><p>Add the HandStates.controller as the animator, and HandController.cs. The script will listen for input from the VR controllers (like trigger press or thumb up) and send signals to the model to animate the hands accordingly. The Animator runs through several Blend Trees to approximate which hand position will most closely match the user&#8217;s motion.</p><h2>Drive Muscles Based on Rotation</h2><p>Forearms were a special case, and I drove them using a script (<a href="https://github.com/AnnieCat/CharacterTools/blob/master/ForearmTwist.cs">ForearmTwist.cs</a>) which simulated the way the radius and ulna rotate around each other. This script gauges the rotation of the hand and drives the rotation of the intermediate forearm bones a percentage of the hand rotation value, so as to create a more gradient twist. It also blends between a series of corrective blendshapes to morph the forearms to a more realistic shape at each 90&#176; of rotation.</p><p>The other muscle deformations (like neck) could be handled by this more generic script (<a href="https://github.com/AnnieCat/CharacterTools/blob/master/GenericRotation.cs">GenericRotation.cs</a>). It is less specific, and simply drives a blendshape based on the value of a bone&#8217;s rotation.</p><p>&lt;blockquote class="imgur-embed-pub" lang="en" data-id="a/xeYTtiB" data-context="false" &gt;&lt;a href="//imgur.com/a/xeYTtiB"&gt;&lt;/a&gt;&lt;/blockquote&gt;&lt;script async src="//s.imgur.com/min/embed.js" charset="utf-8"&gt;&lt;/script&gt;</p><h2>Capture In-Scene Eye Reflections</h2><p>I was using <a href="https://t.umblr.com/redirect?z=https%3A%2F%2Fassetstore.unity.com%2Fpackages%2Ftools%2Fcamera%2Fnvidia-ansel-74758&amp;t=ZjIzYzhkNWI3MzU3ODA3NWI5NGIyMGZmMzhlMWFmNjAwYTRiZWUyOCw3QnVkWVZRcw%3D%3D&amp;b=t%3AJzrcZpU2TvEuTozazUZLEw&amp;p=https%3A%2F%2Fartofmaking.tumblr.com%2Fpost%2F736359664697180160%2Fphotogrammetry-porting-pipeline&amp;m=1&amp;ts=1709559230">Ansel</a> to capture a 360&#176; photo of the Unity scene, from the position I wanted the characters to congregate. I set its values to only capture in black and white, with the levels set that the white threshold was fairly high. I then converted the black parts to transparent, and this became loaded into a cutout shader, which was applied to the outer eye. The outer eye object was linked in its translation, but not rotation to the eye bones, so that when the character moved, there was an accurate simulation of the reflection of the world, and the secularity moved to match if the head rotated, but stayed still if only the eyes rotated.</p><h2>Next Steps</h2><p>This was as far as I got, but had I continued my next steps would have been to</p><ul><li><p>Generate body animations using a VR headset and hand controllers, allowing a person to quickly act out what they wanted the characters to do</p></li><li><p>Capture verbal performance of the person acting (from the oculus microphone) and run that through OVR to automatically generate facial animation</p></li></ul>]]></content:encoded></item><item><title><![CDATA[Events]]></title><description><![CDATA[Notes - Feb 14, 2020 Migrated from Tumblr]]></description><link>https://artofmaking.substack.com/p/events</link><guid isPermaLink="false">https://artofmaking.substack.com/p/events</guid><dc:creator><![CDATA[Annie Drake]]></dc:creator><pubDate>Mon, 04 Mar 2024 13:39:19 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!BhPU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F384e7f1e-e08b-4113-a6c2-86f9a98f4fe5_144x144.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>An event is a message sent to the whole scene.&nbsp; The trumpeter plays taps, everyone goes to bed.&nbsp; Unity has its own custom events - or you can write your own.</p><h2>Unity Events</h2><p>Super simple.&nbsp; Call an event as a variable, and then invoke it wherever you want it to be called.</p><blockquote><p><strong>public UnityEvent OnStart;</strong></p><p><strong>void Start(){</strong></p><p><strong>&nbsp; &nbsp; OnStart.Invoke();</strong></p><p><strong>}</strong></p></blockquote><h2>Custom Events</h2><p>First, I&#8217;m going to make a GameEvent script, which will sit in our scene on an empty gameobject.&nbsp; (Or anywhere we want really)</p><blockquote><p><strong>using System;</strong></p><p><strong>public class GameEvents : Monobehavior{</strong></p><p><strong>&nbsp; &nbsp; public static GameEvents current;<br>&nbsp; &nbsp; private void Awake(){<br>&nbsp; &nbsp; &nbsp; &nbsp; current = this;<br>&nbsp; &nbsp; }</strong></p><p><strong>&nbsp; &nbsp; public event Action onMessageBlast;<br><br>&nbsp; &nbsp; public void Message()<br>&nbsp; &nbsp; {<br>&nbsp; &nbsp; &nbsp; &nbsp; if(onDoorwayTriggerEnter != null){<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; onDoorwayTriggerEnter;<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; }</strong></p><p><strong>}</strong></p></blockquote><p>Next I will create a script to listen for this message and then respond</p><blockquote><p><strong>public class Listener : Monobehavior<br>{<br>&nbsp; &nbsp; void Start(){<br>&nbsp; &nbsp; &nbsp; &nbsp; GameEvents.current.onMessageBlast += onTriggeredEvent;<br>&nbsp; &nbsp; }</strong></p><p><strong>&nbsp; &nbsp; private void onTriggeredEvent(){<br>&nbsp; &nbsp; &nbsp; &nbsp; print(&#8221;I heard your message and my name is&nbsp;&#8220;+this.name);<br>&nbsp; &nbsp; }</strong></p><p><strong>&nbsp; &nbsp; void Update(){<br>&nbsp; &nbsp; &nbsp; &nbsp; if(Input.GetKeyDown(KeyCode.Space)){<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; GameEvents.current.onTriggeredEvent();<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; }<br>}</strong></p></blockquote><p>you want to make sure there&#8217;s something calling it (the update loop) and, and utilize += to subscribe to the message event action.&nbsp; To unsubscribe (do this to avoid clutter if something is deleted) use -=</p><blockquote><p><strong>private void OnDestroy(){<br>&nbsp; &nbsp; GameEvents.current.onMessageBlast -= onTriggeredEvent;<br>}</strong></p></blockquote>]]></content:encoded></item><item><title><![CDATA[Unity Editor Scripts]]></title><description><![CDATA[Notes - Feb 8, 2020 Migrated from Tumblr]]></description><link>https://artofmaking.substack.com/p/unity-editor-scripts</link><guid isPermaLink="false">https://artofmaking.substack.com/p/unity-editor-scripts</guid><dc:creator><![CDATA[Annie Drake]]></dc:creator><pubDate>Mon, 04 Mar 2024 13:37:25 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!BhPU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F384e7f1e-e08b-4113-a6c2-86f9a98f4fe5_144x144.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Editor scripts consist of two different scripts which work together.&nbsp; One which handles our functionality, let&#8217;s call ours <em>MyScript</em>, and another which handles the interface- <em>MyScript_Editor</em>.&nbsp; In our folder where our functionality script is held, add a folder called&nbsp;&#8220;Editor&#8221;, and add our editor script in that.</p><p>To connect them, make sure our editor script is <em>using UnityEditor</em>.&nbsp; Above our class declaration, make it inheret from Editor, instead of monodevelop, and inside declare [CustomEditor(typeof(<em>MyScript</em>))]</p><p>In our editor script, create a function called&nbsp; &nbsp;<br><em><strong>public override void OnInspectorGUI(){}</strong></em> - this gets called each time the editor is drawn.</p><p><strong>MyScript localMyScript = (MyScript)target;</strong>&nbsp;</p><p>will create an instance which you can use to access the variables in your main script.</p>]]></content:encoded></item><item><title><![CDATA[Optimizing Unity for Mobile]]></title><description><![CDATA[Notes - Feb 2, 2020 Migrated from Tumblr]]></description><link>https://artofmaking.substack.com/p/optimizing-unity-for-mobile</link><guid isPermaLink="false">https://artofmaking.substack.com/p/optimizing-unity-for-mobile</guid><dc:creator><![CDATA[Annie Drake]]></dc:creator><pubDate>Mon, 04 Mar 2024 13:36:21 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!BhPU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F384e7f1e-e08b-4113-a6c2-86f9a98f4fe5_144x144.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>High Level</h2><ul><li><p>Keep Vertex count below 100,000</p></li><li><p>Reduce Shaders - utilize texture atlases&nbsp;</p></li><li><p>Reduce thing that need multi-pass renders (reflections, shadows, per pixel lights, transparent objects)</p></li><li><p>Set any non-moving object to static and bake lights wherever possible.</p></li><li><p>Combine all meshes into a single mesh wherever possible (combining meshes which don&#8217;t share the same material is useless)</p></li><li><p>Use Object Pooling rather than instantiate and destroy, and avoid Find() in your code.</p></li><li><p>Avoid creating code that is not re-usable, as it becomes something the garbage collector has to handle, which is CPU intensive.&nbsp; For mobile, a common strategy for managing garbage collector is to ask it to run more frequently, which means its handling less, but you have to run the profiler to make sure this is even helping.&nbsp; Another tactic is to front load your collection at natural gameplay pauses.&nbsp; Incremental garbage collection spreads the work over multiple frames, but in the case that garbage is being constantly created, it can create loops where the GC never turns off.</p></li><li><p>Automate that the artists are adhering to best practices by using the AssetPostprocessor() (enforcing texture limitations, setting your read/write, optimizing game objects ect)</p></li></ul><h2>Debugging</h2><ul><li><p>Use the profiler.&nbsp; Run the game for a time to gather data, and then start turning on and off various things to identify where the bottlenecks are.</p></li><li><p>The GPU is limited by fillrate -&nbsp; number of pixels that can be written to memory per second.&nbsp; Lower display resolution and run game again.</p></li><li><p>The CPU is limited by number of batches to be rendered.&nbsp; You can check your batches using the Rendering Statistics window.</p></li></ul><h2>Batching</h2><ul><li><p>Static gives the best performance - combine all materials into 1 texture.&nbsp; Bake lighting, and set all non-moving objects to static.</p></li><li><p>Follow up with Dynamic. Minimize number of objects and vert count.&nbsp; Don&#8217;t use scale, everything should be at default of 1,1,1.&nbsp; Multipass shaders (like forward and legacy vertex) break batching.</p></li></ul><h2>Audio</h2><ul><li><p>Short Clips (SFX) - Native</p></li><li><p>Longer (looping) clips - compress in memory</p></li><li><p>Music - Stream from disc</p></li><li><p>Files which constantly cause CPU spikes - decompress on load.</p></li></ul><h2>Android</h2><ul><li><p>Run your app on the device, while its connected to the computer, where you can run the profiler from.</p></li><li><p>Test on multiple devices.</p></li><li><p>Avoid putting things in the update loop - put temporary things in coroutines.</p></li><li><p>Reduce UI canvases, and for those you keep, if you do not need to interact remove the graphics raycaster, uncheck Pixel Perfect, and uncheck rich text.</p></li><li><p>Player Settings &gt; Other settings, enable multithreaded rendering.&nbsp; This sends all rendering to another thread.</p></li><li><p>In&nbsp;Quality Settings:</p><ul><li><p>Limit your max high performing calls</p></li><li><p>lower pixel light count to 1 (or 0 if you don&#8217;t have lights)</p></li><li><p>Disable antialiasing</p></li><li><p>Disable soft particles</p></li><li><p>Use hard shadows</p></li><li><p>Set shadow projection to close fit (to avoid hard edges)</p></li><li><p>Set shadow cascades to no cascades</p></li><li><p>lower your shadow distance until is the minimum you can get away with</p></li></ul></li></ul>]]></content:encoded></item><item><title><![CDATA[Transferring Texture Maps in Maya]]></title><description><![CDATA[Note to Self - Jan 4 2020 Migrated from Tumblr]]></description><link>https://artofmaking.substack.com/p/transferring-texture-maps-in-maya</link><guid isPermaLink="false">https://artofmaking.substack.com/p/transferring-texture-maps-in-maya</guid><dc:creator><![CDATA[Annie Drake]]></dc:creator><pubDate>Mon, 04 Mar 2024 13:33:46 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!BhPU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F384e7f1e-e08b-4113-a6c2-86f9a98f4fe5_144x144.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Sometimes you&#8217;re in a position where you want to transfer texture maps from one mesh to another.&nbsp; It&#8217;s fairly simple to do, but requires the materials in Maya to be setup correctly in order to avoid any shading issues.</p><p>Rendering Window |&nbsp; Lighting/Shading &gt; Transfer</p><p>Load your target mesh and source mesh, changing the target mesh&#8217;s search envelope % to 0.5.</p><p>Add whichever maps you want to render, I usually just choose the diffuse, if I&#8217;m transferring texture, although sometimes I&#8217;ll also make a normal map.</p><p>Choose&nbsp;&#8220;use maya common settings&#8221; and then in the Maya common output tab, World Space, Filter Size 3, and for the best detail map set Map width and height to 4096 and then manipulate it in Photoshop.&nbsp; I always set my sampling quality to high, but I&#8217;ve looked at it on low and high and can&#8217;t see too much difference.</p><p>Now for the maps.&nbsp; In your Hypershade, create a Lambert.&nbsp; Load your texture into the incandescence and diffuse slots and set your Color to black.&nbsp; Change Translucence, Translucence Depth, and Translucence Focus to 0.&nbsp; Open up Matte opacity and change it to Solid Matte.&nbsp; Apply this new material to your source object.</p>]]></content:encoded></item><item><title><![CDATA[RealSense SDK and Runtime Libraries]]></title><description><![CDATA[Note to Self - Nov 11, 2015 Migrated from Tumblr]]></description><link>https://artofmaking.substack.com/p/realsense-sdk-and-runtime-libraries</link><guid isPermaLink="false">https://artofmaking.substack.com/p/realsense-sdk-and-runtime-libraries</guid><dc:creator><![CDATA[Annie Drake]]></dc:creator><pubDate>Mon, 04 Mar 2024 13:32:20 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!nGAy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcc58af4-3ceb-4c95-99f4-0839ef7c3332_500x413.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I&#8217;m refactoring some code, where all the components were individually working. &nbsp;Everything was working great, until I tried to add the Perceptual Init calls back in. &nbsp;Then I started to get errors saying things were already defined in&nbsp;<strong>MSVCRT.lib</strong>. &nbsp;</p><p>Seth says that when the compiler is complaining about MS***.lib what&#8217;s going on is that you have multiple libraries which were compiled against different runtime libraries. &nbsp;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!nGAy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcc58af4-3ceb-4c95-99f4-0839ef7c3332_500x413.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!nGAy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcc58af4-3ceb-4c95-99f4-0839ef7c3332_500x413.jpeg 424w, https://substackcdn.com/image/fetch/$s_!nGAy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcc58af4-3ceb-4c95-99f4-0839ef7c3332_500x413.jpeg 848w, https://substackcdn.com/image/fetch/$s_!nGAy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcc58af4-3ceb-4c95-99f4-0839ef7c3332_500x413.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!nGAy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcc58af4-3ceb-4c95-99f4-0839ef7c3332_500x413.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!nGAy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcc58af4-3ceb-4c95-99f4-0839ef7c3332_500x413.jpeg" width="500" height="413" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bcc58af4-3ceb-4c95-99f4-0839ef7c3332_500x413.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:413,&quot;width&quot;:500,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="image" title="image" srcset="https://substackcdn.com/image/fetch/$s_!nGAy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcc58af4-3ceb-4c95-99f4-0839ef7c3332_500x413.jpeg 424w, https://substackcdn.com/image/fetch/$s_!nGAy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcc58af4-3ceb-4c95-99f4-0839ef7c3332_500x413.jpeg 848w, https://substackcdn.com/image/fetch/$s_!nGAy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcc58af4-3ceb-4c95-99f4-0839ef7c3332_500x413.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!nGAy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcc58af4-3ceb-4c95-99f4-0839ef7c3332_500x413.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>If you go into C/C++ tab of the property pages, under Runtime Library you see the option for multi-threaded and multi-threaded DLL. &nbsp;There&#8217;s really only two options- changing those around should fix it.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GV1L!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2640ba87-dcea-4ea9-bc14-90371d36303d_500x380.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GV1L!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2640ba87-dcea-4ea9-bc14-90371d36303d_500x380.jpeg 424w, https://substackcdn.com/image/fetch/$s_!GV1L!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2640ba87-dcea-4ea9-bc14-90371d36303d_500x380.jpeg 848w, https://substackcdn.com/image/fetch/$s_!GV1L!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2640ba87-dcea-4ea9-bc14-90371d36303d_500x380.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!GV1L!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2640ba87-dcea-4ea9-bc14-90371d36303d_500x380.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GV1L!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2640ba87-dcea-4ea9-bc14-90371d36303d_500x380.jpeg" width="500" height="380" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2640ba87-dcea-4ea9-bc14-90371d36303d_500x380.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:380,&quot;width&quot;:500,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="image" title="image" srcset="https://substackcdn.com/image/fetch/$s_!GV1L!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2640ba87-dcea-4ea9-bc14-90371d36303d_500x380.jpeg 424w, https://substackcdn.com/image/fetch/$s_!GV1L!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2640ba87-dcea-4ea9-bc14-90371d36303d_500x380.jpeg 848w, https://substackcdn.com/image/fetch/$s_!GV1L!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2640ba87-dcea-4ea9-bc14-90371d36303d_500x380.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!GV1L!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2640ba87-dcea-4ea9-bc14-90371d36303d_500x380.jpeg 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Sometimes you get lucky and your libraries are labled&#8211; in this case with MD, which refers to <strong>Multi-threaded DLL (/MD)</strong></p>]]></content:encoded></item><item><title><![CDATA[Pair Arrays]]></title><description><![CDATA[Learning - Oct 28, 2015 Migrated from Tumblr]]></description><link>https://artofmaking.substack.com/p/pair-arrays</link><guid isPermaLink="false">https://artofmaking.substack.com/p/pair-arrays</guid><dc:creator><![CDATA[Annie Drake]]></dc:creator><pubDate>Mon, 04 Mar 2024 13:30:27 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!BhPU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F384e7f1e-e08b-4113-a6c2-86f9a98f4fe5_144x144.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I needed to have access to the same [ i ] value across 2 arrays, and was having trouble understanding char* // std::string in C++, so seth shared with me a few different ways to streamline it.</p><blockquote><p><strong>#include &lt;string&gt;<br>#include &lt;vector&gt;<br>#include &lt;map&gt;</strong></p><p><em><strong>// similar to&#8230;HashTable in C# or dictionary in python</strong></em><strong><br>map&lt;string, int&gt; AnimFileMap{ {&#8220;file1&#8221;, 5} };</strong></p><p><em><strong>//accessing map:</strong></em><strong><br>auto timeInMillis = AnimFileMap[&#8220;file1&#8221;];</strong></p><p><em><strong>//or&#8230;</strong></em><strong><br>vector&lt;pair&lt;string, int&gt;&gt; AnimFilePair{ { &#8220;file1&#8221;, 5 } };</strong></p><p><em><strong>//accessing pair:</strong></em><strong><br>auto fileName = AnimFilePair[0].first;<br>auto timeInMillies = AnimFilePair[0].second;</strong></p><p><em><strong>//fun with pairs and typedef (makes things a bit more readable)</strong></em></p><p><strong>typedef pair&lt;string, int&gt; fileinfo_t;<br></strong><em><strong>//so now<br>//vector&lt;fileinfo_t&gt; myfiles;<br>//is the same as<br>//vector&lt;pair&lt;string, int&gt;&gt; myfiles;<br>//<br>//but can be accessed the same way, i.e.<br>// &lt;fileinfo_t&gt;.first and &lt;fileinfo_t&gt;.second</strong></em></p></blockquote>]]></content:encoded></item><item><title><![CDATA[Building for x64 and win32]]></title><description><![CDATA[Sep 29, 2015 Migrated from Tumblr]]></description><link>https://artofmaking.substack.com/p/building-for-x64-and-win32</link><guid isPermaLink="false">https://artofmaking.substack.com/p/building-for-x64-and-win32</guid><dc:creator><![CDATA[Annie Drake]]></dc:creator><pubDate>Mon, 04 Mar 2024 13:29:23 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!BhPU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F384e7f1e-e08b-4113-a6c2-86f9a98f4fe5_144x144.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I ran into a problem where I was trying to combine from two different sample projects, but one was setup to run on x64 and the other on win32. &nbsp;<a href="https://github.com/sgorsten">Sterling </a>explained some rules of thumb when setting up your project properties in Visual Studio.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zAib!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fffc7a70b-dbbc-4d1b-ba52-38b0ea319d5f_500x258.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zAib!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fffc7a70b-dbbc-4d1b-ba52-38b0ea319d5f_500x258.jpeg 424w, https://substackcdn.com/image/fetch/$s_!zAib!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fffc7a70b-dbbc-4d1b-ba52-38b0ea319d5f_500x258.jpeg 848w, https://substackcdn.com/image/fetch/$s_!zAib!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fffc7a70b-dbbc-4d1b-ba52-38b0ea319d5f_500x258.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!zAib!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fffc7a70b-dbbc-4d1b-ba52-38b0ea319d5f_500x258.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zAib!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fffc7a70b-dbbc-4d1b-ba52-38b0ea319d5f_500x258.jpeg" width="500" height="258" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ffc7a70b-dbbc-4d1b-ba52-38b0ea319d5f_500x258.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:258,&quot;width&quot;:500,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="image" title="image" srcset="https://substackcdn.com/image/fetch/$s_!zAib!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fffc7a70b-dbbc-4d1b-ba52-38b0ea319d5f_500x258.jpeg 424w, https://substackcdn.com/image/fetch/$s_!zAib!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fffc7a70b-dbbc-4d1b-ba52-38b0ea319d5f_500x258.jpeg 848w, https://substackcdn.com/image/fetch/$s_!zAib!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fffc7a70b-dbbc-4d1b-ba52-38b0ea319d5f_500x258.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!zAib!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fffc7a70b-dbbc-4d1b-ba52-38b0ea319d5f_500x258.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>In the pulldown tag, you can select for Win32, x64, or all configurations. &nbsp;Here are the general rulesets for the most hit areas:</p><p>C/C++ -&gt; Additional Include Directories</p><p>These are the same for x64 or win32, you want to put your include directory here.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4WJ-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc877392b-57c4-49f3-a010-5b282393f655_500x226.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4WJ-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc877392b-57c4-49f3-a010-5b282393f655_500x226.jpeg 424w, https://substackcdn.com/image/fetch/$s_!4WJ-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc877392b-57c4-49f3-a010-5b282393f655_500x226.jpeg 848w, https://substackcdn.com/image/fetch/$s_!4WJ-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc877392b-57c4-49f3-a010-5b282393f655_500x226.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!4WJ-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc877392b-57c4-49f3-a010-5b282393f655_500x226.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4WJ-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc877392b-57c4-49f3-a010-5b282393f655_500x226.jpeg" width="500" height="226" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c877392b-57c4-49f3-a010-5b282393f655_500x226.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:226,&quot;width&quot;:500,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="image" title="image" srcset="https://substackcdn.com/image/fetch/$s_!4WJ-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc877392b-57c4-49f3-a010-5b282393f655_500x226.jpeg 424w, https://substackcdn.com/image/fetch/$s_!4WJ-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc877392b-57c4-49f3-a010-5b282393f655_500x226.jpeg 848w, https://substackcdn.com/image/fetch/$s_!4WJ-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc877392b-57c4-49f3-a010-5b282393f655_500x226.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!4WJ-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc877392b-57c4-49f3-a010-5b282393f655_500x226.jpeg 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><p>For all these, you want&nbsp;&#8220;Inherit from parent or project defaults&#8221; to be checked.</p><h4>Linker -&gt; General -&gt; Additional Library Directories</h4><p>Here&#8217;s where you list the directories where the .lib belongs. &nbsp;There is often projects where the lib is the same name, but stored in 2 different locations, one named win32 and the other x64. &nbsp;In this case, you can put <strong>$(PlatformTarget) </strong>instead of which directory you want, and visual studio will figure out which one you mean.</p><h4>Linker -&gt; Input -&gt; Additional Dependencies</h4><p>Here&#8217;s where you list against the actual lib files that you&#8217;re linking against. &nbsp;Often, if there&#8217;s a two different .libs, one with a <em>_d</em> after it, the _d version is for debug mode and the other is for release.</p><h4>Editing with *.vcxproj</h4><p>You can also just open up the *.vcxproj file in Notepad++, and that&#8217;s basically an xml file listing all the specifics on the includes. &nbsp;Sterling says that if you take out the conditions, it will just run on all platforms, but that that&#8217;s not an option if you&#8217;re working through the Visual Studio project interface.</p><h4>Notations</h4><p>If you right click your project and say open in explorer, it will show you what <strong>$(ProjectDir)</strong> links to. &nbsp;In some cases, you might need to go up a directory with <strong>..\</strong></p><p>The RealSense SDK builds into Visual Studio that if you want to include its filepath, you can just put <strong>$(RSSDK_DIR)</strong></p>]]></content:encoded></item><item><title><![CDATA[GitIgnore]]></title><description><![CDATA[Note to self - Sep 28, 2015 Migrated from Tumblr]]></description><link>https://artofmaking.substack.com/p/gitignore</link><guid isPermaLink="false">https://artofmaking.substack.com/p/gitignore</guid><dc:creator><![CDATA[Annie Drake]]></dc:creator><pubDate>Mon, 04 Mar 2024 13:26:40 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!BhPU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F384e7f1e-e08b-4113-a6c2-86f9a98f4fe5_144x144.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Super simple, just writing it down so I don&#8217;t have to ask Sterling a third time.</p><p>When uploading to git, make sure to edit the .gitignore file with notepad++, and add the files you want to leave out. &nbsp;Its a good idea to exclude <em>Build</em> and <em>Intermediate</em>, because those each get remade each build.</p><p>If a .gitignore isn&#8217;t readily available (because you&#8217;re uploading for the first time) then when you make your first commit right click something disposable (a .pbt or anything with /debug or /release in the file name) and say ignore, add to .pbt. &nbsp;Once you do that it&#8217;ll make a gitignore file, and then you can open it and add your logic.</p>]]></content:encoded></item><item><title><![CDATA[Visual Studio to Arduino]]></title><description><![CDATA[Project - Sep 28, 2015 Migrated from Tumblr]]></description><link>https://artofmaking.substack.com/p/visual-studio-to-arduino</link><guid isPermaLink="false">https://artofmaking.substack.com/p/visual-studio-to-arduino</guid><dc:creator><![CDATA[Annie Drake]]></dc:creator><pubDate>Mon, 04 Mar 2024 13:25:34 GMT</pubDate><enclosure url="https://substackcdn.com/image/youtube/w_728,c_limit/L4fmp2Ccwxs" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Here I have a signal going from Visual Studio to an Arduino using an Ateml programmer.</p><p>&lt;iframe width="560" height="315" src="</p><div id="youtube2-L4fmp2Ccwxs" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;L4fmp2Ccwxs&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/L4fmp2Ccwxs?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen&gt;&lt;/iframe&gt;</p><p>I just wanted a basic setup ready to go so I could jump in and use it anytime I wanted. &nbsp;Here&#8217;s the <a href="https://github.com/AnnieCat/VisualStudio_to_Arduino">GITHUB </a>repository. &nbsp;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9Lx2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F433cfbbb-5bc8-4c2c-ac22-6a5ab930403e_500x465.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9Lx2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F433cfbbb-5bc8-4c2c-ac22-6a5ab930403e_500x465.jpeg 424w, https://substackcdn.com/image/fetch/$s_!9Lx2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F433cfbbb-5bc8-4c2c-ac22-6a5ab930403e_500x465.jpeg 848w, https://substackcdn.com/image/fetch/$s_!9Lx2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F433cfbbb-5bc8-4c2c-ac22-6a5ab930403e_500x465.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!9Lx2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F433cfbbb-5bc8-4c2c-ac22-6a5ab930403e_500x465.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9Lx2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F433cfbbb-5bc8-4c2c-ac22-6a5ab930403e_500x465.jpeg" width="500" height="465" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/433cfbbb-5bc8-4c2c-ac22-6a5ab930403e_500x465.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:465,&quot;width&quot;:500,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="image" title="image" srcset="https://substackcdn.com/image/fetch/$s_!9Lx2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F433cfbbb-5bc8-4c2c-ac22-6a5ab930403e_500x465.jpeg 424w, https://substackcdn.com/image/fetch/$s_!9Lx2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F433cfbbb-5bc8-4c2c-ac22-6a5ab930403e_500x465.jpeg 848w, https://substackcdn.com/image/fetch/$s_!9Lx2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F433cfbbb-5bc8-4c2c-ac22-6a5ab930403e_500x465.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!9Lx2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F433cfbbb-5bc8-4c2c-ac22-6a5ab930403e_500x465.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"></figcaption></figure></div><p>Here is the physical setup we&#8217;re going to be looking for, and a few things to be aware of.</p><h2>Startup Settings</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8EPW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa29e68f-b105-435a-af20-9bdc8bd84124_500x375.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8EPW!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa29e68f-b105-435a-af20-9bdc8bd84124_500x375.jpeg 424w, https://substackcdn.com/image/fetch/$s_!8EPW!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa29e68f-b105-435a-af20-9bdc8bd84124_500x375.jpeg 848w, https://substackcdn.com/image/fetch/$s_!8EPW!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa29e68f-b105-435a-af20-9bdc8bd84124_500x375.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!8EPW!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa29e68f-b105-435a-af20-9bdc8bd84124_500x375.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8EPW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa29e68f-b105-435a-af20-9bdc8bd84124_500x375.jpeg" width="500" height="375" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/aa29e68f-b105-435a-af20-9bdc8bd84124_500x375.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:375,&quot;width&quot;:500,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="image" title="image" srcset="https://substackcdn.com/image/fetch/$s_!8EPW!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa29e68f-b105-435a-af20-9bdc8bd84124_500x375.jpeg 424w, https://substackcdn.com/image/fetch/$s_!8EPW!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa29e68f-b105-435a-af20-9bdc8bd84124_500x375.jpeg 848w, https://substackcdn.com/image/fetch/$s_!8EPW!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa29e68f-b105-435a-af20-9bdc8bd84124_500x375.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!8EPW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa29e68f-b105-435a-af20-9bdc8bd84124_500x375.jpeg 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><ul><li><p>The computer needs to be reset with <em>Disable driver&nbsp;signature&nbsp;enforcement. </em>Reset your computer with shift held down. &nbsp;Go to Startup Settings, and type&nbsp;&#8216;7&#8242;</p></li><li><p>Connect the Programmer and the Arduino with cables to your computer.</p></li><li><p>The programmer needs to be connected so it can upload the program, and the Arduino needs to be connected so it can receive data.</p></li><li><p>The Anode (long pin) of the LED needs to be in pin 12, not 13.</p></li><li><p>Pin 13 shares functionality with some of the internal mechanisms of the board.</p></li><li><p>Once you use a programmer with your board, it is now flashed and needs a programmer in order to upload.</p></li></ul><p>I didn&#8217;t realize that before, and when I tried to go back to normal serial communication it caused a lot of frustration.</p><p>You need a 6 pin Ateml programmer, not a 12 pin</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!G488!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60ac4115-d141-440f-8d65-a00fbbff5a90_500x188.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!G488!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60ac4115-d141-440f-8d65-a00fbbff5a90_500x188.jpeg 424w, https://substackcdn.com/image/fetch/$s_!G488!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60ac4115-d141-440f-8d65-a00fbbff5a90_500x188.jpeg 848w, https://substackcdn.com/image/fetch/$s_!G488!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60ac4115-d141-440f-8d65-a00fbbff5a90_500x188.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!G488!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60ac4115-d141-440f-8d65-a00fbbff5a90_500x188.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!G488!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60ac4115-d141-440f-8d65-a00fbbff5a90_500x188.jpeg" width="500" height="188" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/60ac4115-d141-440f-8d65-a00fbbff5a90_500x188.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:188,&quot;width&quot;:500,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="image" title="image" srcset="https://substackcdn.com/image/fetch/$s_!G488!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60ac4115-d141-440f-8d65-a00fbbff5a90_500x188.jpeg 424w, https://substackcdn.com/image/fetch/$s_!G488!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60ac4115-d141-440f-8d65-a00fbbff5a90_500x188.jpeg 848w, https://substackcdn.com/image/fetch/$s_!G488!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60ac4115-d141-440f-8d65-a00fbbff5a90_500x188.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!G488!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60ac4115-d141-440f-8d65-a00fbbff5a90_500x188.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div>]]></content:encoded></item></channel></rss>