<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Fabric Engine Inc</title>
	<atom:link href="http://fabricengine.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://fabricengine.com</link>
	<description>Experts in Digital Content Creation tools</description>
	<lastBuildDate>Fri, 17 May 2013 23:10:59 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Creation Platform Workshop</title>
		<link>http://fabricengine.com/2013/05/creation-platform-workshop/</link>
		<comments>http://fabricengine.com/2013/05/creation-platform-workshop/#comments</comments>
		<pubDate>Thu, 16 May 2013 15:39:41 +0000</pubDate>
		<dc:creator>Paul Doyle</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://fabricengine.com/?p=4225</guid>
		<description><![CDATA[This is an in-depth presentation for coders that covers the key concepts of Creation Core and Creation Platform. It starts with a couple of demonstrations, and then moves onto the actual workshop. 00:20 &#8211; Asset Browser demo 06:30 &#8211; rigging/animation tool demo 19:20 &#8211; Introducing the Core 44:20 &#8211; Registered Types 53:00 &#8211; Wrapping the [...]]]></description>
				<content:encoded><![CDATA[<p><a href="http://fabricengine.com/2013/05/creation-platform-workshop/"><em>Click here to view the embedded video.</em></a></p>
<p>This is an in-depth presentation for coders that covers the key concepts of Creation Core and Creation Platform. It starts with a couple of demonstrations, and then moves onto the actual workshop.</p>
<p>00:20 &#8211; Asset Browser demo</p>
<p>06:30 &#8211; rigging/animation tool demo</p>
<p>19:20 &#8211; Introducing the Core</p>
<p>44:20 &#8211; Registered Types</p>
<p>53:00 &#8211; Wrapping the core</p>
<p>58:40 &#8211; Introducing Creation Platform</p>
<p>The code samples can be found on github at: <a href="https://github.com/fabric-engine/UsergroupWorkshops">https://github.com/fabric-engine/UsergroupWorkshops</a></p>
<p>Accompanying articles:</p>
<p><a title="Creation Platform 102 : Introduction to Creation Platform" href="http://fabricengine.com/2012/11/creation-platform-102-building-custom-tools-using-creation-platform/">Part 1</a></p>
<p><a title="Creation Platform 102 : The relationship between the Core and Creation Platform" href="http://fabricengine.com/2012/11/creation-platform-102-the-relationship-between-the-core-and-creation-platform/">Part 2</a></p>
]]></content:encoded>
			<wfw:commentRss>http://fabricengine.com/2013/05/creation-platform-workshop/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Creation 1.0.32 has arrived!</title>
		<link>http://fabricengine.com/2013/02/creation-1-0-32-has-arrived/</link>
		<comments>http://fabricengine.com/2013/02/creation-1-0-32-has-arrived/#comments</comments>
		<pubDate>Wed, 06 Feb 2013 16:58:59 +0000</pubDate>
		<dc:creator>Paul Doyle</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://fabricengine.com/?p=3841</guid>
		<description><![CDATA[Hi everyone – we’re pleased to announce that Creation Platform 1.0.32 is ready for download. You can get the software from here *IMPORTANT NOTE FOR UPGRADING FROM 1.0.31* Due to some changes between versions, you must uninstall 1.0.31 before installing the new release. Creation Platform now requires OpenGL 3.2 or later. Thanks, Team Fabric 1.0.32 [...]]]></description>
				<content:encoded><![CDATA[<p>Hi everyone – we’re pleased to announce that Creation Platform 1.0.32 is ready for download.</p>
<p><span style="font-size: 13px; line-height: 19px;">You can get the software from <a href="http://dist.fabric-engine.com/CreationPlatform/latest/">here</a></span></p>
<p><span style="font-size: 13px; line-height: 19px;">*</span><strong style="font-size: 13px; line-height: 19px;">IMPORTANT NOTE FOR UPGRADING FROM 1.0.31</strong><span style="font-size: 13px; line-height: 19px;">*</span></p>
<ul>
<li><span style="font-size: 13px; line-height: 19px;">Due to some changes between versions, you </span><span style="text-decoration: underline;">must</span><span style="font-size: 13px; line-height: 19px;"> uninstall 1.0.31 before installing the new release.</span></li>
<li><span style="font-size: 13px; line-height: 19px;">Creation Platform now requires OpenGL 3.2 or later.</span></li>
</ul>
<p>Thanks,</p>
<p>Team Fabric</p>
<h3><strong><span style="text-decoration: underline;">1.0.32 Release notes:</span></strong></h3>
<p><strong>Supported Platforms</strong></p>
<ul>
<li>Mac OS X is once again a fully-supported platform. The real-time renderer has been updated to use the OpenGL 3.2 profile, which is required for OS X support.</li>
<li>We now officially support a Windows 7 64-bit Python 2.6 build.</li>
<li>The other supported platforms have remained the same. The complete list is:
<ul>
<li>Windows 7 64-bit using Python 2.7</li>
<li>Windows 7 64-bit using Python 2.6</li>
<li>Windows 7 32-bit using Python 2.7</li>
<li>Ubuntu 12.04 (Python 2.7)</li>
<li>Ubuntu 10.04 (Python 2.6)</li>
<li>CentOS 6.3 (Python 2.6)</li>
<li>Mac OS X 10.7 &#8220;Lion&#8221; or later (Python 2.7)</li>
</ul>
</li>
</ul>
<h3><strong>Creation Platform Changes</strong></h3>
<p><strong> </strong><strong style="font-size: 13px; line-height: 19px;">Real-time Renderer Framework</strong></p>
<ul>
<li>Avoid recomputation of valid render targets (for example: don’t recompute a shadow map if we orbit the camera)</li>
<li>Multiple fixes related to supporting dynamic pass changes (for example: from exposed pass options)</li>
<li>Support for Boolean and flags as input arguments of render callbacks, and boolean as shader params</li>
<li>Removed implicit construction of projection matrices (based on bounding volumes); now built explicitly by pass render function callbacks</li>
<li>Support for cube map render targets (used for point light shadows), including new &#8216;refineTextureTarget&#8217; render pass statement</li>
<li>Octree queries for spheres and transformed bounding boxes</li>
<li>Improvement of the RTR documentation</li>
<li>All shaders are now updated to comply with OpenGL 3.2 profile.</li>
</ul>
<p><strong> </strong><strong style="font-size: 13px; line-height: 19px;">Real-time Renderer Passes and Shaders</strong></p>
<ul>
<li>Support for orthographic cameras</li>
<li>Shadows for all light types (directional, point and spot), including infinite lights, with various global controls exposed by the passes. Implementation of 3-level cascaded shadow maps for directional lights.</li>
<li>Adjustment of the near/far planes of cameras and shadow maps based on the view frustum and scene bbox for more precision</li>
<li>Integration of our SSAO and bloom in the standard passes. The effects themselves can be improved but provide a great example for the RTR</li>
<li>Per-instance support for culling and double-sided shading, including an option to revert the culling if negative scaling (like in some DCCs)</li>
<li>Reduction of deferred shading render target memory (Z (depth) instead of full positions + more optimal texture formats)</li>
</ul>
<p><strong> </strong><strong style="font-size: 13px; line-height: 19px;">Scene Graph</strong></p>
<ul>
<li>Refactoring of the lights in 3 python classes with improved construction options (PointLight, SpotLight and DirectionalLight)</li>
<li>The Image node class hierarchy was refactored to store pixels in a registered type. this makes querying of pixel values from within KL code easy. An example &#8216;Displacement Deformer&#8217; was added that demonstrates deforming a mesh using pixel values.</li>
<li>The Alembic exporter has been updated and now supports a wider range of scenarios.</li>
<li>Refactored our reference interface system. Now each node maintains a list of InPorts and OutPorts. These can be used to navigate the graph and explicitly create connections between nodes.</li>
<li>Fixes to Curve Editor Framing, and background grid drawing.</li>
<li>A collection of minor bugs were fixed.</li>
</ul>
<p><strong> </strong><strong style="font-size: 13px; line-height: 19px;">DCC Integration</strong></p>
<ul>
<li>Support for Maya 2013 integration on Linux</li>
</ul>
<p><strong> </strong><strong style="font-size: 13px; line-height: 19px;">Licensing</strong></p>
<ul>
<li>RLM floating licenses are now per-host and not per-process. This is not a change in Creation Platform but rather in our license generation settings; any user who wants their previous floating license updated to be per-host instead of per-process can contact us.</li>
</ul>
<p><strong> </strong><strong style="font-size: 13px; line-height: 19px;">Creation Core Changes</strong></p>
<ul>
<li>CAPI: Add support for calls into Creation Core from different threads in the client</li>
<li>Fix optimized code cache on machines running in non-US locales</li>
<li>A few small Python client fixes that could cause crashes on invalid input.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://fabricengine.com/2013/02/creation-1-0-32-has-arrived/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Creation and Creation Modules</title>
		<link>http://fabricengine.com/2013/01/creation-and-creation-modules/</link>
		<comments>http://fabricengine.com/2013/01/creation-and-creation-modules/#comments</comments>
		<pubDate>Mon, 28 Jan 2013 19:11:48 +0000</pubDate>
		<dc:creator>Paul Doyle</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://fabricengine.com/?p=3779</guid>
		<description><![CDATA[Hi everyone – after taking a look at the business model for Creation, and getting feedback from various customers, we are making some changes to the business model for Creation. We are reducing the price for the Creation framework, and introducing separate Creation Module products that we will offer in the future. We wanted to [...]]]></description>
				<content:encoded><![CDATA[<p>Hi everyone – after taking a look at the business model for Creation, and getting feedback from various customers, we are making some changes to the business model for Creation. We are reducing the price for the Creation framework, and introducing separate Creation Module products that we will offer in the future. We wanted to explain the logic behind this change, as we think it offers some significant benefits over the current &#8216;$3k for everything&#8217; license that we have been proposing.</p>
<p>Problems with the old model:</p>
<ul>
<li>Customers find the $3k price point very high for simple tools like asset viewers and other widgets. It means that everyone wants to see significant value before they can justify purchasing Creation &#8211; yet we started the company so that we could cover both large and small problems.</li>
<li>This in turn means that we have to keep adding functionality to create sufficient value to justify the purchase – this has meant that we are getting further away from offering a framework and heading towards to the monolithic DCC applications that we never intended to replicate.</li>
<li>Bundling crowds, muscles, vegetation systems etc within the framework is not efficient – in many cases this functionality just gets ignored.</li>
<li>Customers want to use Creation for non-interactive/headless scenarios, but cannot justify paying thousands for these licenses. It&#8217;s very difficult to do create a split between interactive and non-interactive licenses with Creation &#8211; the things that make the framework powerful, also make it difficult to create arbitrary separations like this.</li>
<li>3<sup>rd</sup> party developers are unable to build and sell simple, useful tools with Creation because of the price point. Part of our plan has always been to support and develop a strong 3rd party developer ecosystem, but the business model has made that impossible.</li>
</ul>
<p><span style="text-decoration: underline;">Our solution:</span></p>
<ul>
<li>Release the core framework without all of the high-end application samples – so muscles, crowds, vegetation etc are removed.</li>
<li>Release this functionality as standalone modules that are more complete products, and charge for them separately.</li>
</ul>
<p><span style="text-decoration: underline;">Benefits:</span></p>
<ul>
<li>Studios can start using Creation for simple tools with a low cost of entry &#8211; $250 per license, per year</li>
<li>Development of the core Creation framework will be faster, with a focus on performance and flexibility</li>
<li>We can put more work into various modules, as we can get a clear return on investment by selling them to customers that need the functionality</li>
<li>3<sup>rd</sup> party developers can sell standalone applications and modules at a much lower cost</li>
</ul>
<p><span style="text-decoration: underline;">What is/isn’t in the basic Creation framework?</span></p>
<ul>
<li>Muscles, SSR, Crowds, Hair, Vegetation will all be removed from the Creation framework and offered as modules (over time)</li>
<li>Generically useful functionality will always be in the core product – so real-time rendering, file extensions, DCC integration, UI functionality, Creation Core Execution Engine, debug tools etc etc. Everything you&#8217;d need if you decided you wanted to build your own modules</li>
</ul>
<div><span style="text-decoration: underline;">New pricing</span></div>
<p>Creation:</p>
<p>Annual rental: $250 per year, per node &#8211; a node can run anywhere (artist machine, render node etc)</p>
<p>Purchase: $750 purchase + $100 annual subs</p>
<p><em>We will still offer the two free licenses of Creation!</em></p>
<p>Volume discounts/Site licensing: <a href="mailto:sales@fabricengine.com">contact us</a></p>
<p>Modules: We will announce module pricing as we release them.</p>
]]></content:encoded>
			<wfw:commentRss>http://fabricengine.com/2013/01/creation-and-creation-modules/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>German Creation Platform Workshop successfully finished!</title>
		<link>http://fabricengine.com/2012/12/first-creation-platform-workshop-successfully-finished/</link>
		<comments>http://fabricengine.com/2012/12/first-creation-platform-workshop-successfully-finished/#comments</comments>
		<pubDate>Tue, 11 Dec 2012 13:21:54 +0000</pubDate>
		<dc:creator>Helge Mathee</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://fabricengine.com/?p=3703</guid>
		<description><![CDATA[Hey folks, just as a heads up: We did it. The Creation Platform workshop at Sehsucht was an overall success. The feedback was great, the attendees as well as myself enjoyed the presentation and the general vibe was very creative. It was particularly interesting to see the ideas and prospective projects come to life once [...]]]></description>
				<content:encoded><![CDATA[<p><img src="http://fabricengine.com/wp-content/uploads/2012/12/DSC0300.jpg" alt="" title="Lots of notebooks getting ready" width="740" class="aligncenter wp-image-3700" /></p>
<p>Hey folks,</p>
<p>just as a heads up: We did it. The Creation Platform workshop at <a href="http://www.sehsucht.de" title="Sehsucht">Sehsucht</a> was an overall success. The feedback was great, the attendees as well as myself enjoyed the presentation and the general vibe was very creative. </p>
<p><img src="http://fabricengine.com/wp-content/uploads/2012/12/DSC0301.jpg" alt="" title="Andrew MacPherson and Christian Fritz" width="420" class="alignright wp-image-3701" /></p>
<p>It was particularly interesting to see the ideas and prospective projects come to life once the inner workings of Creation Platform had been explained and layed out.</p>
<p><img src="http://fabricengine.com/wp-content/uploads/2012/12/DSC0280.jpg" alt="" title="Post event drinks" width="420" class="alignright wp-image-3698" /></p>
<p>Providing Server Side Rendering without any friction, allowing tools to be used as well as standalone as inside of Softimage or Maya&#8230; all of these subjects kept people excited throughout the workshop. We are very proud to say that our vision is shared by our users!</p>
<p>A special thanks again to <a href="http://www.sehsucht.de" title="Sehsucht">Sehsucht</a> for hosting the event. Their location is quite amazing and helped the casual and family-like feeling for the event. The IT did an amazing job as well, providing everything requested. </p>
<p>Thanks to all of the attendees for coming. We hope to see you again soon!</p>
<p>The Fabric Engine team.</p>
<p><img src="http://fabricengine.com/wp-content/uploads/2012/12/DSC0312.jpg" alt="" title="Lots of notebooks getting ready" width="740" class="aligncenter wp-image-3700" /></p>
]]></content:encoded>
			<wfw:commentRss>http://fabricengine.com/2012/12/first-creation-platform-workshop-successfully-finished/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Creation Platform 102 : The relationship between the Core and Creation Platform</title>
		<link>http://fabricengine.com/2012/11/creation-platform-102-the-relationship-between-the-core-and-creation-platform/</link>
		<comments>http://fabricengine.com/2012/11/creation-platform-102-the-relationship-between-the-core-and-creation-platform/#comments</comments>
		<pubDate>Tue, 20 Nov 2012 18:33:15 +0000</pubDate>
		<dc:creator>Phil Taylor</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://fabricengine.com/?p=3580</guid>
		<description><![CDATA[In this tutorial, we will go over the basic concepts of the Core dependency graph, and build a model of how Creation Platform relates to the Core. We will build a simple Core dependency graph with some trivial operators, and then build a simple abstraction using Python classes to aid in the construction of the graph. The following post [...]]]></description>
				<content:encoded><![CDATA[<p>In this tutorial, we will go over the basic concepts of the Core dependency graph, and build a model of how Creation Platform relates to the Core.</p>
<p>We will build a simple Core dependency graph with some trivial operators, and then build a simple abstraction using Python classes to aid in the construction of the graph.</p>
<p>The following post is based on a workshop presented at the Montreal Fabric Engine user group. All of the source code can be found online in the repository location:</p>
<p><a title="https://github.com/fabric-engine/UsergroupWorkshops/tree/master/WorkshopNovember2012/IntroductionToTheCore" href="https://github.com/fabric-engine/UsergroupWorkshops/tree/master/WorkshopNovember2012/IntroductionToTheCore" target="_blank">https://github.com/fabric-engine/UsergroupWorkshops/tree/master/WorkshopNovember2012/IntroductionToTheCore</a></p>
<p>This is an article to accompany the workshop video &#8211; you can see it <a href="https://vimeo.com/groups/fabric/videos/53952929">here</a>. The first part of this tutorial is <a title="Creation Platform 102 : Introduction to Creation Platform" href="http://fabricengine.com/2012/11/creation-platform-102-building-custom-tools-using-creation-platform/">here</a>.</p>
<h2>1 . Building a Basic Dependency Graph</h2>
<p>In the following example, we build a trivial dependency graph</p>
<pre class="brush: python; title: ; notranslate">
import FabricEngine.Core

fabricClient = FabricEngine.Core.createClient()
timerNode = fabricClient.DG.createNode('timer')
timerNode.addMember('time', 'Scalar', 0)
valuesDGNode = fabricClient.DG.createNode('data')
valuesDGNode.addMember('values', 'Scalar[]')
valuesDGNode.addMember('valueCount', 'Integer', 100)
valuesDGNode.setDependency(timerNode, 'timer')
# The operator that will create our particles
operator = fabricClient.DG.createOperator('ComputeDataOp')
operator.setEntryPoint('computeDataOp')
operator.setSourceCode(open('dataCalculator.kl').read())
# We instanciate a Binding object. It will glue the data with the operator.
binding = fabricClient.DG.createBinding()
binding.setOperator(operator)

binding.setParameterLayout([
  'timer.time',
  'self.index',
  'self.valueCount',
  'self.values'
])

valuesDGNode.bindings.append(binding)

print timerNode.getErrors()
print valuesDGNode.getErrors()

for i in range(0, 100):
  print 'At frame:', i
  timerNode.setData('time', float(i))
  valuesDGNode.evaluate()
print &quot;======================&quot;
</pre>
<p>What the code does above builds a trivial dependency graph. The timer node stores a value which is used to compute an array of values in the values node.<br />
<a href="http://fabricengine.com/2012/11/creation-platform-102-the-relationship-between-the-core-and-creation-platform/basic-graph-3/" rel="attachment wp-att-3603"><img class="alignnone size-full wp-image-3603" title="Basic Graph" src="http://fabricengine.com/wp-content/uploads/2012/11/Basic-Graph2.png" alt="" width="586" height="211" /></a></p>
<h2>2. Data Parallel Nodes</h2>
<pre class="brush: python; title: ; notranslate">
import FabricEngine.Core

fabricClient = FabricEngine.Core.createClient()

timerNode = fabricClient.DG.createNode('timer')
timerNode.addMember('time', 'Scalar', 0)
valuesDGNode = fabricClient.DG.createNode('data')
valuesDGNode.addMember('values', 'Scalar[]')
valuesDGNode.addMember('valueCount', 'Integer', 100)
valuesDGNode.setDependency(timerNode, 'timer')
# The operator that will create our particles
operator = fabricClient.DG.createOperator('ComputeDataOp')
operator.setEntryPoint('computeDataOp')
operator.setSourceCode(open('dataCalculator.kl').read())

# We instanciate a Binding object. It will glue the data with the operator.
binding = fabricClient.DG.createBinding()
binding.setOperator(operator)

binding.setParameterLayout([
  'timer.time',
  'self.index',
  'self.valueCount',
  'self.values'
])

valuesDGNode.bindings.append(binding)

print timerNode.getErrors()
print valuesDGNode.getErrors()

#####################################
# 2. Data based parallelizm

# By setting the slice count of a node to 100, the node's data mambers are
# all duplicate by 100 times, and the bound operator will evaluate once for
# each slice. This gives us an easy method of 'instancing' a node many times.
valuesDGNode.setCount(10)

for i in range(0, 100):
  print 'At frame:', i
  timerNode.setData('time', float(i))
  valuesDGNode.evaluate()

print &quot;======================&quot;

</pre>
<p><a href="http://fabricengine.com/2012/11/creation-platform-102-the-relationship-between-the-core-and-creation-platform/basic-slicedgraph-2/" rel="attachment wp-att-3604"><img class="alignnone size-full wp-image-3604" title="Basic SlicedGraph" src="http://fabricengine.com/wp-content/uploads/2012/11/Basic-SlicedGraph1.png" alt="" width="616" height="374" /></a></p>
<p>The data node slice count has now been increased, effectively giving us 10 instances of the Data Node. The operator bound to the Data Node is now evaluated for each slice of the node. Each slice of the data node contains a unique set of data which can be computed independently.</p>
<h2>3. Python Abstraction Classes</h2>
<pre class="brush: python; title: ; notranslate">
#####################################
# 3. Wrapping the Core DG elements in Python classes

import FabricEngine.Core

class TimerNode(object):

  def __init__(self, client):

    # The dependency graph node is a private member
    # that can only be accessed via accessor methods.
    self.__timerNode = client.DG.createNode('timer')
    self.__timerNode.addMember('time', 'Scalar', 0)
    self.__dependents = []

  def getDGNode(self):
    return self.__timerNode

  def addDependent(self, node):
    self.__dependents.append(node)

  def evaluateTimeRange(self):
    # To trigger evaluations of the Core graph, we modify
    # the values tored in the Timer node, and then trigger
    # evaluations in the dependent nodes.
    # Note: generally graph evaluations are triggered by rendering
    # or export processes. Manual evaluation of graphs is not usually required.
    for i in range(0, 100):
      print 'At frame:', i
      self.__timerNode.setData('time', float(i))
      for dep in self.__dependents:
        dep.evaluate()
class DataCalculator(object):

  __numDataCalculators = 0
  __operator = None

  def __init__(self, client, valueCount=1, sliceCount=1):
    # Core dependency graph nodes must have unique names.
    # Construct a Dependency Graph node, giving it a
    # unique name for each instance of DataCalculator.
    self.__class__.__numDataCalculators += 1
    self.__valuesDGNode = client.DG.createNode('data' + str(self.__class__.__numDataCalculators))
    self.__valuesDGNode.addMember('values', 'Scalar[]')
    self.__valuesDGNode.addMember('valueCount', 'Integer', valueCount)
    # By setting the slice count of a node to 100, the node's data mambers are all duplicated
    # by 100 times, and the bound operator will evaluate once for each slice.
    # This gives us an easy method of 'instancing' a node many times.
    self.__valuesDGNode.setCount(sliceCount)

    # Compile the shared operator.
    # The operator is a class variable as it can be shared
    # amongst all instances of DataCalculator, meaning the KL code
    # is only compiled once.
    if self.__class__.__operator is None:
      self.__class__.__operator = client.DG.createOperator('ComputeDataOp')
      self.__class__.__operator.setEntryPoint('computeDataOp')
      self.__class__.__operator.setSourceCode(open('dataCalculator.kl').read())

    # We instantiate a Binding object. It will glue the data with the operator.
    binding = client.DG.createBinding()
    binding.setOperator(self.__class__.__operator)

    binding.setParameterLayout([
      'timer.time',
      'self.index',
      'self.valueCount',
      'self.values'
    ])

    self.__valuesDGNode.bindings.append(binding)

  def setTimerNode(self, timerNode):
    # Create a relatonship between the TimerNode and the DataCalculator,
    # so the timeer can update the calculator when the time value changes.
    self.__valuesDGNode.setDependency(timerNode.getDGNode(), 'timer')
    timerNode.addDependent(self)

  def evaluate(self):
    self.__valuesDGNode.evaluate()
fabricClient = FabricEngine.Core.createClient()

timerNode = TimerNode(fabricClient)
myDataCalculator1 = DataCalculator(fabricClient, valueCount=200, sliceCount=5)
myDataCalculator2 = DataCalculator(fabricClient, valueCount=500, sliceCount=7)
myDataCalculator1.setTimerNode(timerNode)
myDataCalculator2.setTimerNode(timerNode)

timerNode.evaluateTimeRange()

print &quot;======================&quot;
</pre>
<p>Rather than building the dependency graph nodes directly, we can use Python classes to construct the dependency graph. The Python classes defined in the graph above are used to generate the dependency graph nodes, making it easy to build graphs quickly. The Python classes can create small parts of a bigger dependency graph. The Python classes define  re-usable sub-graphs which can be shared across projects.<br />
<a href="http://fabricengine.com/2012/11/creation-platform-102-the-relationship-between-the-core-and-creation-platform/pastparallel-slicedgraph-2/" rel="attachment wp-att-3605"><img class="alignnone size-full wp-image-3605" title="PastParallel SlicedGraph" src="http://fabricengine.com/wp-content/uploads/2012/11/PastParallel-SlicedGraph1.png" alt="" width="649" height="639" /></a></p>
<pre>The dependency graph nodes constructed by the Python classes are kept as private members. Python can then be used to provide a level of abstraction, facilitating the construction of larger dependency graphs. This simple example is analogous to Creation Platform. Creation Platform is a collection of Python classes which are used to build Creation Core dependency graphs.</pre>
<h2>4. Registering Custom Data Types</h2>
<p>One of the key features of the Creation Core is the ability to define custom data types that can then be used in the dependency graph. All complex data types used in Creation Platform are custom types registered at runtime. This means that our Vectors, Quaternions, and Matrices are all defined as custom types at runtime, and can therefore be modified, and extended according to your requirements.</p>
<p>The way type registration works, is a Python class is defined with a collection of methods for working with that class in the Python environment. This Python class is then registered with the Core, and equivalent KL methods are specified for working with the same type in KL.</p>
<pre class="brush: python; title: ; notranslate">
fabricClient = FabricEngine.Core.createClient()

class Vec2():
  def __init__( self, x = None, y = None ):
    if type( x ) is float and type( y ) is float:
      self.x = x
      self.y = y
    elif x is None and y is None:
      self.x = 0
      self.y = 0
    else:
      raise Exception( 'Vec2: invalid arguments' )

  def sum( self ):
    return self.x + self.y

  def add(self, other):
    return Vec2(x = self.x + other.x, \
    y = self.y + other.y)

  def __str__(self):
    return &quot;Vec2(x = &quot; + str(self.x) + &quot;, y = &quot; + str(self.y) + &quot;)&quot;

desc = {
  'members': [ { 'x':'Scalar' }, { 'y':'Scalar' } ],
  'constructor': Vec2,
  'klBindings': {
  'filename': &quot;(inline)&quot;,
  'sourceCode': &quot;\
function Vec2(Scalar x, Scalar y)\n\
{\n\
 this.x = x;\n\
 this.y = y;\n\
}\n\
\n\
function Vec2 + (Vec2 a, Vec2 b) {\n\
 return Vec2(a.x + b.x, a.y + b.y);\n\
}\n\
function Scalar Vec2.sum() {\n\
 return this.x + this.y;\n\
}\n\
&quot;
 }
}

fabricClient.RegisteredTypesManager.registerType( 'Vec2', desc )

newVec2_1 = Vec2(3.4, 7.2)
newVec3_2 = Vec2(2.6, 17.5)

print newVec2_1.add(newVec3_2)
print (newVec2_1.add(newVec3_2)).sum()
node = fabricClient.DependencyGraph.createNode(&quot;foo&quot;)
node.addMember( 'vec2_1', 'Vec2' )
node.addMember( 'vec2_2', 'Vec2' )
node.setData( 'vec2_1', 0, newVec2_1 )
node.setData( 'vec2_2', 0, newVec3_2 )
# The operator that will create our particles
operator = fabricClient.DG.createOperator('addVec2')
operator.setEntryPoint('addVec2')
operator.setSourceCode(open('vec2Add.kl').read())

# We instanciate a Binding object. It will glue the data with the operator.
binding = fabricClient.DG.createBinding()
binding.setOperator(operator)

binding.setParameterLayout([
  'self.vec2_1',
  'self.vec2_2'
])
node.bindings.append(binding)
print node.getErrors()
node.evaluate()
print &quot;======================&quot;
</pre>
<p>The code sample above defines a type called Vec2, and some basic methods on that type for manipulating the data. The type is then registered with the Core, along with a collection of kl methods for operating on the Vec2 in KL. The same math can then be computed in KL, or in Python giving the same results.</p>
<p><em>Note: Often data structures are defined where the methods defined in Python and KL are completely different. The Animation system is made up of a collection of registered types where the methods in Python are used to manipulate the animation tracks, generate, or remove keys, and the methods in KL are performance critical, such as evaluation of the tracks. This enables Python to be used for user interfaces and data manipulation, and KL for data evaluation.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://fabricengine.com/2012/11/creation-platform-102-the-relationship-between-the-core-and-creation-platform/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Creation Platform 102 : Introduction to Creation Platform</title>
		<link>http://fabricengine.com/2012/11/creation-platform-102-building-custom-tools-using-creation-platform/</link>
		<comments>http://fabricengine.com/2012/11/creation-platform-102-building-custom-tools-using-creation-platform/#comments</comments>
		<pubDate>Tue, 20 Nov 2012 18:32:51 +0000</pubDate>
		<dc:creator>Phil Taylor</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://fabricengine.com/?p=3615</guid>
		<description><![CDATA[The following post is based on a workshop presented at the Montreal Fabric Engine user group. All of the source code can be found online in the repository location: https://github.com/fabric-engine/UsergroupWorkshops/tree/master/WorkshopNovember2012/IntroductionToTheCore You can watch a video presentation of the complete workshop here. Defining a Custom Creation Platform Application Defining a Custom Scene Graph Node Scene Graph Nodes [...]]]></description>
				<content:encoded><![CDATA[<p>The following post is based on a workshop presented at the Montreal Fabric Engine user group. All of the source code can be found online in the repository location:</p>
<p><a title="https://github.com/fabric-engine/UsergroupWorkshops/tree/master/WorkshopNovember2012/IntroductionToTheCore" href="https://github.com/fabric-engine/UsergroupWorkshops/tree/master/WorkshopNovember2012/IntroductionToTheCore" target="_blank">https://github.com/fabric-engine/UsergroupWorkshops/tree/master/WorkshopNovember2012/IntroductionToTheCore</a></p>
<p>You can watch a video presentation of the complete workshop <a href="https://vimeo.com/groups/fabric/videos/53952929">here</a>.</p>
<h2>Defining a Custom Creation Platform Application</h2>
<pre class="brush: python; title: ; notranslate">

import math, random
from PySide import QtGui, QtCore

from MandelbrotImage import MandelbrotImage

from FabricEngine.CreationPlatform.PySide import *
class MandelBrotViewerApp(Basic3DDemoApplication):

  def __init__(self):
      super(MandelBrotViewerApp, self).__init__(
      setupGlobalTimeNode = True,
      setupSelection = False,
      setupUndoRedo = True,
      setupPersistence = True,
      enableRaycasting = True,
      setupImport = True
    )

   self.setWindowTitle(&quot;MandelBrot Viewer App&quot;)
   self.constructionCompleted()

MandelBrotViewerApp().exec_()

</pre>
<h2>Defining a Custom Scene Graph Node</h2>
<pre>Scene Graph Nodes are python classes that define the structure of the Creation Platform's scene graph. There is a wide range of scene graph nodes defined in Creation Platform, making it easy to take one of the base nodes types and extend it according to your own requirements.
In this example, we define a new custom Image node that display a generated mandelbrot set. The MandelbrotImage node exposes a time port enabling it to be connected to time nodes so it can be driven by the time value.
<pre class="brush: python; title: ; notranslate">
from FabricEngine.CreationPlatform.Nodes.Images.Image2DImpl import Image2D
from FabricEngine.CreationPlatform.Nodes.Animation.TimeImpl import Time

class MandelbrotImage(Image2D):

  def __init__(self, scene, **options):

    ###########################################
    # 1.0 Setup the base image

    options.setdefault('width', 640)
    options.setdefault('height', 480)
    options.setdefault('format', 'RGB')
    options.setdefault('createSlicedDGNode', True)
    options.setdefault('forceRefresh', True)

    super(MandelbrotImage, self).__init__(scene, **options)

    ###########################################
    # 2.0 Setup the parameters for the madelbrot set.
    imageAttributesDGNode = self.getAttributesDGNode()

    imageAttributesDGNode.addMember(&quot;center&quot;, &quot;Complex64&quot;, Complex64(0.0, 0.0))
    imageAttributesDGNode.addMember(&quot;zoom&quot;, &quot;Float64&quot;, 1.0)
    imageAttributesDGNode.addMember(&quot;maxIterations&quot;, &quot;Size&quot;, 1536)

    self._addMemberInterface(imageAttributesDGNode, 'center', True)
    self._addMemberInterface(imageAttributesDGNode, 'zoom', True)
    self._addMemberInterface(imageAttributesDGNode, 'maxIterations', True)

    ###########################################
    # 3.0 Setup the pixels node.
    pixelsDGNode = self.getPixelsDGNode()
    pixelsDGNode.setDependency(imageAttributesDGNode, 'parameters')

    self.bindDGOperator(pixelsDGNode.bindings,
      name = 'resizeNode',
      fileName = FabricEngine.CreationPlatform.buildAbsolutePath('Mandelbrot.kl'),
      layout = [
        'self',
        'attributes.width',
        'attributes.height',
      ]
    )
    self.bindDGOperator(pixelsDGNode.bindings,
      name = 'generateMandelbrot',
      fileName = FabricEngine.CreationPlatform.buildAbsolutePath('Mandelbrot.kl'),
      layout = [
        'self.pixels',
        'attributes.center',
        'attributes.zoom',
        'attributes.maxIterations',
        'self.index',
        'attributes.width',
        'attributes.height',
      ]
    )

    ###########################################
    # 4.0 Setup time reference

    self.__timeOpBindings = None
    def __changeTimeNode(data):
      if data['prevNode'] is not None and data['node'] is None:
        if self.__timeOpBindings is not None:
          self.removeDGOperatorBinding(imageAttributesDGNode.bindings, self.__timeOpBindings)

        imageAttributesDGNode.removeDependency('time')
      if data['node'] is not None:
        imageAttributesDGNode.setDependency(data['node'].getDGNode(), 'time')
        self.__timeOpBindings = self.bindDGOperator(imageAttributesDGNode.bindings,
          name = 'setTime',
          sourceCode = 'operator setTime(Scalar time, io Float64 zoom){ zoom = 1.0 + time; }',
          layout = [
            'time.time',
            'self.zoom'
          ]
        )

    self.addReferenceInterface('Time', Time, False, __changeTimeNode)
###########################################
# 5.0 Register the new custom node so that it will show up in the
# user interfaces, and be saved and loaded with the scene files.

MandelbrotImage.registerNodeClass('MandelbrotImage')

</pre>
<ol>
<li>The base class constructor can be invoked with parameters to setup an empty image node.</li>
<li>New members can be added to the dependency graph node defined in the base class. The 'AddMemberInterface' methods expose the specified values on the user interface of the node.</li>
<li>Operators are bound to the dependency graph node that will compute the pixel values of the mandelbrot set.</li>
<li>A 'reference interface is added to the node, enabling the node to be connected to Time nodes, to drive the zoom value of the mandelbrot set.</li>
</ol>
<p>The resulting MandelbrotImage node can then be constructed in the node graph and connected to the background texture port on the Viewport node.</p>
<p><a href="http://fabricengine.com/2012/11/creation-platform-102-building-custom-tools-using-creation-platform/mandelbrotbackground/" rel="attachment wp-att-3628"><img class="alignnone  wp-image-3628" title="MandelbrotBackground" src="http://fabricengine.com/wp-content/uploads/2012/11/MandelbrotBackground.jpg" alt="" width="1067" height="554" /></a></p>
<p>The next part of this tutorial can be found <a href="http://fabricengine.com/2012/11/creation-platform-102-the-relationship-between-the-core-and-creation-platform/">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://fabricengine.com/2012/11/creation-platform-102-building-custom-tools-using-creation-platform/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Workshop, Hamburg, 8th of Dec.</title>
		<link>http://fabricengine.com/2012/11/workshop-event-hamburg-8th-of-dec/</link>
		<comments>http://fabricengine.com/2012/11/workshop-event-hamburg-8th-of-dec/#comments</comments>
		<pubDate>Mon, 19 Nov 2012 10:50:55 +0000</pubDate>
		<dc:creator>Helge Mathee</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://fabricengine.com/?p=3637</guid>
		<description><![CDATA[Hey gang! I am happy to announce the first official Creation Platform workshop in Germany. Date: 8th of December 2012 Location: Sehsucht, Laeiszstrasse 13–15, Hamburg. In this workshop we will go through the details of: What&#8217;s the Creation Core? Multithreading approaches The core&#8217;s language KL Creation Platform Implementation of a custom node Integration into a [...]]]></description>
				<content:encoded><![CDATA[<p>Hey gang!</p>
<p>I am happy to announce the first official Creation Platform workshop in Germany.</p>
<p><strong>Date: 8th of December 2012</strong><br />
<strong>Location: <a title="http://www.sehsucht.de/about" href="http://www.sehsucht.de/about" target="_blank">Sehsucht</a>, Laeiszstrasse 13–15, Hamburg. </strong></p>
<p>In this workshop we will go through the details of:</p>
<ul>
<li>What&#8217;s the Creation Core?</li>
<li>Multithreading approaches</li>
<li>The core&#8217;s language KL</li>
</ul>
<ul>
<li>Creation Platform</li>
<li>Implementation of a custom node</li>
<li>Integration into a DCC (such as Maya or Softimage)</li>
</ul>
<p>Please bring linux (ubuntu 64), windows (win7 64) or OSX based laptops.</p>
<p><strong>We&#8217;re sorry, this event is now fully booked.</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://fabricengine.com/2012/11/workshop-event-hamburg-8th-of-dec/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Creation Platform 101</title>
		<link>http://fabricengine.com/2012/10/creation-platform-101/</link>
		<comments>http://fabricengine.com/2012/10/creation-platform-101/#comments</comments>
		<pubDate>Wed, 17 Oct 2012 17:58:40 +0000</pubDate>
		<dc:creator>Paul Doyle</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://fabricengine.com/?p=3253</guid>
		<description><![CDATA[Introduction In this series of articles we would like to explain basic but extremely important concepts used by Creation Platform to build a 3D application. In the first part, we will only use the Fabric Core from its python module, to build the dependency graph (without using Creation Platform). This will give you the picture on the low level subjects first. Taking this path will [...]]]></description>
				<content:encoded><![CDATA[<h3 dir="ltr">Introduction</h3>
<p><a href="http://fabricengine.com/2012/10/creation-platform-101/"><em>Click here to view the embedded video.</em></a></p>
<p>In this series of articles we would like to explain basic but extremely important concepts used by <em>Creation Platform</em> to build a 3D application.</p>
<p>In the first part, we will only use the <em>Fabric Core</em> from its python module, to build the dependency graph (without using <em>Creation Platform). </em>This will give you the picture on the low level subjects first. Taking this path will help you to quickly understand some key concepts that are abstracted in <em>Creation Platform</em>. We will build a super simple particle system and will visualize it from a command line interface.</p>
<p>In the second part you will learn how to take advantage of such high performance systems for an interactive particle simulation application. <em>Creation Platform</em> will helps us in various areas, as it will provide all of the tools to build a user interface, but it will also help us to build a more complex dependency graph (and more easily), as well as providing a much better debugging environment.</p>
<p dir="ltr"><a title="Creation Platform 101: The Core Dependency Graph" href="http://fabricengine.com/2012/10/test/">Part1  The Core Dependency Graph</a></p>
<p dir="ltr"><a title="Creation Platform 101: Building a Particle System with Creation" href="http://fabricengine.com/2012/10/creation-platform-101-building-a-particle-system-with-creation/">Part2  Building a Particle System with Creation Platform</a></p>
]]></content:encoded>
			<wfw:commentRss>http://fabricengine.com/2012/10/creation-platform-101/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Creation Platform 101: Building a Particle System with Creation</title>
		<link>http://fabricengine.com/2012/10/creation-platform-101-building-a-particle-system-with-creation/</link>
		<comments>http://fabricengine.com/2012/10/creation-platform-101-building-a-particle-system-with-creation/#comments</comments>
		<pubDate>Wed, 17 Oct 2012 17:58:13 +0000</pubDate>
		<dc:creator>Paul Doyle</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Tutorials]]></category>

		<guid isPermaLink="false">http://fabricengine.com/?p=3338</guid>
		<description><![CDATA[Note: This tutorial comes with full source code that can be found here: https://github.com/frenchdog/CreationPlatform101.git Now that you know how to build a dependency graph, we will build on what you learned and create a more interactive particle system. We will design a simple system that will allow us to move an emitter and play with some [...]]]></description>
				<content:encoded><![CDATA[<p dir="ltr"><em>Note: This tutorial comes with full source code that can be found here:</em><a title="CreationPlatform101" href="https://github.com/frenchdog/CreationPlatform101.git" target="_blank"> https://github.com/frenchdog/CreationPlatform101.git</a></p>
<p dir="ltr">
<p dir="ltr">Now that you know <a title="Creation Platform 101: The Core Dependency Graph" href="http://fabricengine.com/2012/10/test/">how to build a dependency graph</a>, we will build on what you learned and create a more interactive particle system. We will design a simple system that will allow us to move an emitter and play with some of the parameters using a graphical user interface. We will use the Euler method to solve the motion of our particles. This system will use an openGL viewport to visualize the particles and widgets to edit various parameters like the emission rate and the randomization of the velocity.</p>
<p dir="ltr">Here is a list of the objects we need to design:</p>
<ul>
<li>Emitters: Generate initial particle attributes like velocity or position. The emitters can be of various shape e.g a disc, sphere etc</li>
<li>Forces: Will modify particle velocity. Can be as simple as a directional force, or something more complex, such as a field.</li>
<li>Simulator: Generates particles and computes their positions for each time step.</li>
</ul>
<div>These three types of objects will give us the opportunity to take a look at Creation Platform classes like the SceneGraphNode, the Component, and the PointCloud (which is more specialized). We will also discuss the Creation Platform Application classes that handle services like the timeline, persistence, and undo-redo.</div>
<h2 dir="ltr">The SceneGraphNode class:</h2>
<p>This is the main building block in Creation. This node lets you package various DG nodes needed for one specific task. You can connect SceneGraphNodes together using the reference system. Referencing a node is <span style="text-decoration: underline;">not</span> the same thing as connecting two DGNodes together &#8211; which is what we covered in the first tutorial using setDependency() &#8211; referencing a SceneGraphNode gives you access to all the DGNodes of the referenced node. You can access every DGNode of a referenced SceneGraphNode, but some dependencies may not make sense. For example, connecting the rotation of a Transform Node to the point positions of a Geometry node would return an error. The node referencing system ensures that only valid connections between SceneGraphNodes are established. Using this system, you can build very complex graphs yet keep things nicely organised &#8211; as you can see by opening the SceneGraph Debugger:</p>
<p><a href="http://fabricengine.com/2012/10/creation-platform-101-building-a-particle-system-with-creation/scenegraph/" rel="attachment wp-att-3398"><img class="alignnone  wp-image-3398" title="SceneGraph" src="http://fabricengine.com/wp-content/uploads/2012/10/SceneGraph.png" alt="" width="644" height="268" /></a></p>
<p>Compared to the true Dependency Graph that you can visualize using the Dependency Graph Debugger :</p>
<p><a href="http://fabricengine.com/2012/10/creation-platform-101-building-a-particle-system-with-creation/dependencygraph-2/" rel="attachment wp-att-3402"><img class="alignnone  wp-image-3402" title="DependencyGraph" src="http://fabricengine.com/wp-content/uploads/2012/10/DependencyGraph1.png" alt="" width="643" height="279" /></a></p>
<p>The SceneGraph is an abstraction of the Core dependency graph that lets you construct your scene much more easily. The SceneGraph only exists within Creation Platform, it is not represented in the Core (since it is an abstraction of the `true`dependency graph).</p>
<p>To create a new node you can either derive it from the SceneGraphNode class or use a subclass of SceneGraphNode (like PolygonMesh or PointCloud). These classes create the DGNodes and data members needed for these primitives. You can also augment an existing class by applying a Component. A Component can add additional DGNodes, Operators and References to an existing SceneGraphNode (we will build our particle system node using this approach).</p>
<p>Choosing to subclass a SceneGraphNode or to apply a new Component is a matter of choice that can vary per project. In the particle system that we are building we will create a new SceneGraphNode type for the emitter. You will see that this approach means that we will only be able to connect this type of node to the emitter input of our particle system.</p>
<p>Now that you understand the difference between the Core Dependency Graph and the Creation SceneGraph lets build our particle system!</p>
<h2 dir="ltr">The Force class:</h2>
<p>We will define a simple force here. This shows us how to create a single DGNode in Creation Platform.</p>
<pre class="brush: python; title: ; notranslate">
class Force(SceneGraphNode):
&quot;&quot;&quot; A simple Directional Force Class &quot;&quot;&quot;
  def __init__(self, scene, **options):
    super(Force, self).__init__(scene, **options)
    self.constructDGNode()
    self.getDGNode().addMember( 'direction', 'Vec3', options.setdefault('direction',Vec3(1, 0, 0)) )
    self._addMemberInterface(self.getDGNode(), 'direction', True)
    self.getDGNode().addMember('intensity', 'Scalar', options.setdefault('intensity',10))
    self._addMemberInterface(self.getDGNode(), 'intensity', defineSetter = True)
</pre>
<p>&#8220;constructDGNode(&#8216;myName&#8217;)&#8221; build a &#8230; DGNode inside our SceneGraphNode. But this method doesn&#8217;t just call FabricCoreClient.DG.createNode() like we saw in the first article, it is also adding a &#8220;getMyNameDGNode&#8221; instance method to any instances of the class. Since we didn&#8217;t provide a name, the instance method is just called &#8220;getDGNode&#8221;. But when a SceneGraphNode uses more than one DGNode, it makes sense to use more explicit names for every constructed DGNode.</p>
<p>After we add a member to a DGNode, we can expose data contained in it on our class using &#8220;_addMemberInterface&#8221;. An Interface is a system that lets you get and (optionally set) a DGNode member from your python code <strong>AND</strong> from the graphical user interface of the Creation application. This reflection between your python code the running application is very useful as you can inspect any exposed DG members from the UI.</p>
<p>You maybe already noticed that every SceneGraphNode&#8217;s &#8220;__init__&#8221; method uses **options as one of its argument. This let you pass any number of arguments to your subclass using keyword arguments (like kwarg=value). For example, if I use &#8220;options['direction']&#8220; in the class object, it will return a value only if I create my class instance like this : force = Force( direction=Vec3(0,5,0) ). If &#8216;direction&#8217; is not passed in the instance, its construction will fail. This is why we use options.setdefault( &#8216;direction&#8217;, Vec3(10,0,0) ). It will return Vec3(0,5,0) if it is passed as an argument, else it will use the default value Vec3(10,0,0).</p>
<h2 dir="ltr">The Emitter class:</h2>
<p>An emitter will generate some points. Those points will be added to our simulated point cloud each time an emitter create new ones. Creation provides a class called Points, and it provides all the services we need to display our points in the viewport. By inheriting from this class, the Emitter class will just need to define the &#8216;shape&#8217; of those points positions.</p>
<p>First, we are going to create an &#8216;abstract&#8217; base class for our emitter. The idea is to be able to connect various type of emitters to our particle system. So if we tell this system to reference any SceneGraphNode of type &#8220;BaseParticleEmitter&#8221;, it should validate the connection for and only for every BaseParticleEmitter subclasses.<br />
- Note that we didn&#8217;t create a Base class for the Force node, but you should also create one if you want to use more than one type of Force in your simulation -</p>
<pre class="brush: python; title: ; notranslate">
class BaseParticleEmitter(Points):

&quot;&quot;&quot; A simple emitter system to define initial values for a particle system&quot;&quot;&quot;

def __init__(self, scene, **options):

# ensure that base class is never instantiated
 if self.__class__.__name__ == 'BaseParticleEmitter':
   raise FabricEngine.CreationPlatform.SceneGraphException('You cannot instantiate the BaseParticleEmitter node directly.')

# call the baseclass constructor
 super(BaseParticleEmitter, self).__init__(scene, **options)

self.addValue('points_count', 'Size', options.setdefault('pointCount', 100), addGetterSetterInterface=True)
 self.addValue('initial_velocity', 'Vec3', Vec3(0,10,0), addGetterSetterInterface=True)
 self.addValue('initial_velocity_variance', 'Vec3', Vec3(1.0, 0.0, 1.0), addGetterSetterInterface=True)

def __setTimeNode(data):
 timeController = data['node']
 self.getGeometryDGNode().setDependency( timeController.getDGNode(), 'time')
 self.addReferenceInterface(name='Time', cls=BaseTime, isList=False, changeCallback=__setTimeNode)

if options.setdefault('time', None) is not None:
 self.setTimeNode(options['time'])

# the Time class doesn't store the fps in its DG node. It is a standard python attribute that we set into the emitter node
 fps = self.getTimeNode().getFPS()
 self.addValue('fps', 'Scalar', fps)
</pre>
<p>As we are inheriting from the Points class, we can use some handy methods like &#8220;addValue()&#8221; and &#8220;addAttribute()&#8221;. The &#8220;addValue()&#8221; method lets you add a uniform data member to the node (a single value of any supported type) and &#8221;addAttribute()&#8221; lets you add some geometry attributes for each point. Currently attributes only support the type Scalar, so to define a Vec3 per point, you just specify the number of components you want in the &#8220;addAttribute()&#8221; method &#8211; note that this is a temporary limitation as more complex types will be handled by the GeometryAttributes in the future.</p>
<p>Using the &#8220;addReferenceInterface()&#8221; method, we can set a reference to another node, in this case the scene Global Time Node, that is created by the Creation Platform application (as we will see later on). Setting the reference creates a connection between the Particle Emitter and the Time node. But it doesn&#8217;t create any dependency with Time&#8217;s DGNode(s). You must pass a callback function to addReferenceInterface() that will set the dependency on one or more DGNode. This callback will be called when you &#8220;set the reference&#8221;. Here, we named this reference &#8220;Time&#8221;  so we can set it using the instance method named &#8216;setTimeNode&#8217;. The &#8216;setTimeNode&#8217; argument can only by of type &#8216;Time&#8217;, trying to connect another class will raise an error like this :</p>
<p>&#8220;FabricEngine.CreationPlatform.SceneGraphException: Reference &#8216;Time&#8217; only supports nodes of type &#8216;BaseTime&#8217;&#8221;</p>
<p>Next we will implement a concrete class for one of our particle emitters. We will create a disc emitter, and it will include its own manipulator to be placed interactively in a 3D view.</p>
<pre class="brush: python; title: ; notranslate">
class DiscEmitter(BaseParticleEmitter):

&quot;&quot;&quot; A specialized Particle Emitter using a circle primitive for interactive manipulation &quot;&quot;&quot;

def __init__(self, scene, **options):

# call the baseclass constructor
 super(DiscEmitter, self).__init__(scene, **options)

self.addValue('seed', 'Integer', 123, addGetterSetterInterface = True)

# add a manipulator
 self.circle = LinesCircle(scene, radius=1.0)
 self.circleXform = Transform(scene, globalXfo=Xfo(Vec3(0.0,0.0,0.0)))
 self.circleMaterial = Material(scene, xmlFile='FlatLinesMaterial')
 self.circleMaterial.addPreset(name='blueLines', color=Color(0.35,0.75,0.95), lineWidth = 1.0)
 self.circleInstance = GeometryInstance(scene,
 geometry=self.circle,
 transform=self.circleXform,
 material=self.circleMaterial
 )

 def onConnectCircleXform(data):
   circleXform = data['node']
   self.getGeometryDGNode().setDependency( circleXform.getDGNode(), 'transform')

 self.addReferenceInterface('Transform', Transform, False, onConnectCircleXform)
 self.setTransformNode(options.setdefault('emitterXform', self.circleXform))

 self.bindDGOperator(self.getGeometryDGNode().bindings,
 name = 'DiscEmitterGenerator',
 fileName = FabricEngine.CreationPlatform.buildAbsolutePath('ParticleEmitters.kl'),
 layout = [
 'self.attributes',
 'time.time',
 'self.fps',
 'self.points_count',
 'self.seed',
 'self.initial_velocity',
 'self.initial_velocity_variance',
 'transform.localXfo'
 ],
 )
</pre>
<p>The disc emitter will emit some points randomly into a unit circle, so we define a &#8220;seed&#8221; value that will be exposed in the UI to let the user edit the random distribution. Then we add a Circle that is a built in primitive in Creation. The circle will help visualize the emitter limits. As we want to interactively move this circle, we add it to an Instance node. The Instance node combines a Transform and a Geometry node to represent a single Instance of a shape at a given position in space. We set a reference with the Transform node as we will need it to move the created particles. Then we can create our first KL operator. If you remember correctly, in the first part we learned that we need to instantiate a DGNode, a Binding and an Operator to then glue those objects together. In Creation Platform it is simpler as you can use the &#8220;bindDGOperator()&#8221; method instead. You just need to define the DGNode you want to attach the operator to, the name of the KL operator you want to use, the path to the KL file and the Parameter Layout.</p>
<p>In this layout, &#8216;self&#8217; always refer to the node used in the first argument. &#8216;transform&#8217; can be also used as we set a reference to this node.</p>
<p>And now the KL code for our emitter :</p>
<pre class="brush: jscript; title: ; notranslate">
operator DiscEmitterGenerator(
 io GeometryAttributes attributes,
 in Scalar time,
 in Scalar fps,
 in Size pointCount,
 in Integer seed,
 in Vec3 initialVelocity,
 in Vec3 initialVelocityVariance,
 in Xfo emitterLocalXfo
) {
 attributes.addStandardAttributes( true, true );
 attributes.resize(pointCount);

AttributeKey velocityAttrKey = attributes.getKey(&quot;velocities&quot;);
 if(velocityAttrKey.type == AttributeType_Invalid)
 velocityAttrKey = attributes.addScalarAttribute(&quot;velocities&quot;, 3);

Integer offset = fps*time + seed;
 executeParallel(
 setParticleOnDisc_perPoints,
 pointCount, offset,
 attributes.scalarAttributes[Attribute_Pos],
 attributes.scalarAttributes[velocityAttrKey.index],
 initialVelocity,
 initialVelocityVariance,
 emitterLocalXfo
 );
}
</pre>
<p>GeometryAttributes is a type that let you access a specific attribute using its name (the attribute key). You can resize it and all of its attributes will be resized accordingly. For example, if we want 100 particles then we set attributes.resize( 100 ) and it will set the size for the velocities array to 300 (we set the number of components for the velocities attribute to three).</p>
<p>As we are executing the &#8221;setParticleOnDisc_perPoints()&#8221; function in parallel, this function is using an integer as its first argument. In the implementation of the function, it will be the current index in the array of data we want to evaluate. When we call the function, this integer define the size of the array.</p>
<p>The KL code for the &#8221;setParticleOnDisc_perPoints&#8221; :</p>
<pre class="brush: jscript; title: ; notranslate">
function setParticleOnDisc_perPoints(
 in Size index,
 in Integer offset,
 io ScalarAttribute positionsAttr,
 io ScalarAttribute velocitiesAttr,
 in Vec3 initialVelocity,
 in Vec3 initialVelocityVariance,
 in Xfo emitterLocalXfo
){
 Index i = 0;
 Vec3 position;
 do {
 position = Vec3( mathRandomScalar(index, offset + i) - 0.5, 0.0, mathRandomScalar(index, offset + i + 500) - 0.5 );
 i+=1;
 } while (position.lengthSquared() &gt; 0.25 &amp; i &lt; 1000);

 Index voff = index * 3;
 position *= 2;

position = emitterLocalXfo.transformVector( Vec3(position) );
 positionsAttr.setVec3Value(voff, Vec3(position.x, position.y, position.z));

Vec3 rndInitVelocity = initialVelocity;
 rndInitVelocity.x += (mathRandomScalar(index, 123) - 0.5) * initialVelocityVariance.x;
 rndInitVelocity.y += (mathRandomScalar(index, 345) - 0.5) * initialVelocityVariance.y;
 rndInitVelocity.z += (mathRandomScalar(index, 456) - 0.5) * initialVelocityVariance.z;
 rndInitVelocity = emitterLocalXfo.ori.rotateVector( Vec3(rndInitVelocity) );
 velocitiesAttr.setVec3Value(index * 3, rndInitVelocity);
}
</pre>
<p>This function generates a random position in a circle. This position is then transformed in the space of the Circle (used by the manipulator). Next, the attribute position is set using this Vec3 value and finally the velocity is set.</p>
<h2 dir="ltr">The SimulatedParticleComponent class:</h2>
<p>This is the central station of our particle simulation. We will use a SimulatedPoints type as this class provide various attributes used in simulation like the velocity. However, in this case we won&#8217;t create a new type as it will be used as a standard simulated points node by any SceneGraphNode referencing it. For this scenario, adding a Component is the best option.</p>
<p>You can apply a Component to a SceneGraphNode like that : <span style="color: #800000;">mySceneGraphNode.addComponent( myComponent( someOptions ) )</span><br />
The &#8220;addComponent()&#8221; method of a SceneGraphNode will add a reference to this SceneGraphNode in the instantiated Component. This way the component can take the control of the node and can add any needed feature. To access the node from the component class, you can use self._node.</p>
<p>Let&#8217;s take a look at the added feature applied by the &#8220;SimulatedParticleComponent&#8221; to build our particle system:</p>
<pre class="brush: python; title: ; notranslate">
class SimulatedParticleComponent(Component):

&quot;&quot;&quot; A component to add a simple euler integration solver on a SimulatedPoints node&quot;&quot;&quot;

def __init__(self, **options):
 super(SimulatedParticleComponent, self).__init__(**options)

@staticmethod
 def canApplyTo(node):
 return isinstance(node, SimulatedPoints)

def apply(self, points):
 super(SimulatedParticleComponent, self).apply(points)

self._node.addValue('gravity', 'Vec3', Vec3(0.0, -9.81, 0.0), True)
 self._node.addValue('ageLimit', 'Scalar', 3.0, True)
 self._node.addValue('randomizeAgeLimit', 'Scalar', 0.25, True)
 self._node.setValueInterfaceOption('randomizeAgeLimit', 'uiRange', Vec2(0, 1))
 self._node.addValue('startColor', 'Color', Color(0.0, 0.2, 0.8), True)
 self._node.addValue('endColor', 'Color', Color(0.0, 0.0, 0.0), True)
 self._node.addValue('randomizeColor', 'Scalar', 0.25, True)
 self._node.setValueInterfaceOption('randomizeColor', 'uiRange', Vec2(0, 1))

self._node.addReferenceInterface(name='Emitter', cls=BaseParticleEmitter, isList=False, changeCallback=self.__onChangeEmitterCallback)
 self._node.setEmitterNode(self._getOption('emitter'))

self._node.addReferenceInterface(name='Force', cls=Force, isList=False, changeCallback=self.__onChangeForceCallback)
 self._node.setForceNode(self._getOption('force'))

# Operators bindings
 self._node.bindDGOperator(self._node.getGeometryDGNode().bindings,
 name = 'SimulatedParticleOp',
 fileName = FabricEngine.CreationPlatform.buildAbsolutePath('SimulatedParticleComponent.kl'),
 layout = [
 'self.attributes',
 'time.time',
 'time.timeStep',
 'emitter.attributes',
 'self.gravity',
 'force.direction',
 'force.intensity'
 ])

self._node.bindDGOperator(self._node.getGeometryDGNode().bindings,
 name = 'SetParticleColorOp',
 fileName = FabricEngine.CreationPlatform.buildAbsolutePath('SimulatedParticleComponent.kl'),
 layout = [
 'self.attributes',
 'self.ageLimit',
 'self.randomizeAgeLimit',
 'self.randomizeColor',
 'self.startColor',
 'self.endColor'
 ])

def __onChangeEmitterCallback(self, data):
 emitter = data['node']
 self._node.getGeometryDGNode().setDependency( emitter.getGeometryDGNode(), 'emitter')

def __onChangeForceCallback(self, data):
 force = data['node']
 self._node.getGeometryDGNode().setDependency( force.getDGNode(), 'force')
</pre>
<p>As you can see, velocities and gravity data is added to our PointCloud. References to the Time, Emitter and Force nodes are set and a &#8220;SimulatedParticleOp&#8221; operator is added.</p>
<p>Here is the KL code for this operator:</p>
<pre class="brush: jscript; title: ; notranslate">
function addPoints(
 in Scalar time,
 io GeometryAttributes attributes,
 in GeometryAttributes emitterAttributes,
 in AttributeKey velocityAttrKey,
 in AttributeKey emitterVelocityAttrKey
) {
 if(time==0) {
 attributes.resize(emitterAttributes.size());
 attributes.scalarAttributes[Attribute_Pos].data = emitterAttributes.scalarAttributes[Attribute_Pos].data.clone();
 attributes.scalarAttributes[velocityAttrKey.index].data = emitterAttributes.scalarAttributes[emitterVelocityAttrKey.index].data.clone();
 }
 else {

Size previousSize = attributes.size();
 Size newSize = attributes.size() + emitterAttributes.size();
 attributes.resize(newSize);
 attributes.scalarAttributes[velocityAttrKey.index].incrementVersion();

for(Index i=0; i&lt; emitterAttributes.size(); i++)
 {
 Index emitterIndex = i * 3;
 Index particlesIndex = (i + previousSize) * 3;

attributes.scalarAttributes[Attribute_Pos].data[particlesIndex+0] = emitterAttributes.scalarAttributes[Attribute_Pos].data[emitterIndex+0];
 attributes.scalarAttributes[Attribute_Pos].data[particlesIndex+1] = emitterAttributes.scalarAttributes[Attribute_Pos].data[emitterIndex+1];
 attributes.scalarAttributes[Attribute_Pos].data[particlesIndex+2] = emitterAttributes.scalarAttributes[Attribute_Pos].data[emitterIndex+2];

attributes.scalarAttributes[velocityAttrKey.index].data[particlesIndex+0] = emitterAttributes.scalarAttributes[emitterVelocityAttrKey.index].data[emitterIndex];
 attributes.scalarAttributes[velocityAttrKey.index].data[particlesIndex+1] = emitterAttributes.scalarAttributes[emitterVelocityAttrKey.index].data[emitterIndex+1];
 attributes.scalarAttributes[velocityAttrKey.index].data[particlesIndex+2] = emitterAttributes.scalarAttributes[emitterVelocityAttrKey.index].data[emitterIndex+2];
 }
 }
}

function eulerIntegration_perPoints(
 in Index index,
 in Scalar time,
 in Scalar timestep,
 io ScalarAttribute positionsAttr,
 io ScalarAttribute velocitiesAttr,
 io ScalarAttribute ageAttr,
 in Vec3 force ) {

if(time == 0) {
 ageAttr.setScalarValue(index, 0, 0.0);
 }
 else {
 Vec3 newVelocity = velocitiesAttr.getVec3Value(index * 3) + force * timestep;

Vec3 newPosition = positionsAttr.getVec3Value(index * 3);
 newPosition += newVelocity * timestep;

positionsAttr.setVec3Value(index * 3, newPosition);
 velocitiesAttr.setVec3Value(index * 3, newVelocity);
 Scalar age = ageAttr.getScalarValue(index, 0);
 age+=timestep;
 ageAttr.setScalarValue(index, 0, age);
 }
}

operator SimulatedParticleOp(
 io GeometryAttributes attributes,
 in Scalar time,
 in Scalar timestep,
 in GeometryAttributes emitterAttributes,
 in Vec3 gravity,
 in Vec3 force,
 in Scalar intensity
) {

AttributeKey velocityAttrKey = attributes.getKey(&quot;velocities&quot;);
 AttributeKey emitterVelocityAttrKey = emitterAttributes.getKey(&quot;velocities&quot;);

AttributeKey ageAttrKey = attributes.getKey( &quot;age&quot; );
 if( ageAttrKey.type == AttributeType_Invalid )
 ageAttrKey = attributes.addScalarAttribute( &quot;age&quot;, 1);

// Scalar initAges[];
 // initAges.resize(attributes.size());
 // attributes.scalarAttributes[ageAttrKey.index].data = initAges;

addPoints( time, attributes, emitterAttributes, velocityAttrKey, emitterVelocityAttrKey);

executeParallel(
 eulerIntegration_perPoints,
 attributes.size,
 time,
 timestep,
 attributes.scalarAttributes[Attribute_Pos],
 attributes.scalarAttributes[velocityAttrKey.index],
 attributes.scalarAttributes[ageAttrKey.index],
 gravity+force.unit()*intensity
 );

}
</pre>
<p>We finished the description for all the objects needed to created our particle system. Lets build a demo application to test it now !</p>
<h2 dir="ltr">The CreationPlatformApplication class:</h2>
<p>Here is a drawing showing the general structure of a Creation Platform Application:</p>
<p style="text-align: center;"><a href="http://fabricengine.com/2012/10/creation-platform-101-building-a-particle-system-with-creation/creation-platform-3d-application-classes-2/" rel="attachment wp-att-3765"><img class="aligncenter  wp-image-3765" title="Creation Platform 3D Application Classes" src="http://fabricengine.com/wp-content/uploads/2012/10/Creation-Platform-3D-Application-Classes1.png" alt="" width="746" height="570" /></a></p>
<p>Those applications let you enable some common services very easily. For our particle simulation demo, we would like an undo-redo system, a timeline, being able to save the scene and to export the particles (using the Alembic exporter). All those feature are enable using keyword arguments in the __init__ function :</p>
<pre class="brush: python; title: ; notranslate">
class ParticleSystemDemo(CreationPlatformApplication):
 def __init__(self):

 super(ParticleSystemDemo, self).__init__(
 setupGlobalTimeNode=True,
 setupSelection=True,
 cameraPosition=Vec3(19.0,13.0,-4.0),
 cameraTarget=Vec3(0.0,2.0,0.0),
 setupUndoRedo=True,
 timeRange=Vec2(0.0,10.0),
 timeAsSeconds=False,
 setupPersistence=True,
 setupExport=True
 )
</pre>
<p>Then we can setup the simple particle system:</p>
<pre class="brush: python; title: ; notranslate">
# build the Particle System
 particles = SimulatedPoints(scene, name='Particles', time=time)
 emitter = DiscEmitter(scene, pointCount=200, time=time)
 force = Force(scene, direction=Vec3(1,0,0), intensity=0)
 particles.addComponent(SimulatedParticleComponent(emitter=emitter, force=force))
</pre>
<p>To be able to access easily any SceneGraphNodes, another Python object called Scene is used.<br />
It is always required when you instantiate a SceneGraphNode. The scene let you access a node like this : camera = scene.getNode(&#8216;Camera&#8217;)</p>
<h2>Conclusion</h2>
<p>As you can see, we built a Particle Simulation system with just one type of emitter and one type of force &#8211; the purpose of this tutorial was to understand key principles first &#8211; but it could be a good exercise for the reader to add some other types. Also, we did not deal with multiple emitters/forces referencing. It is not very complex but it was too much to cover in 101 course. We will see how to deal with this problem in a future tutorial.</p>
<p>We hope you enjoy being able to create you own particle system from scratch using Creation Platform. Comments are welcome !</p>
<p>If you&#8217;re signed up to our beta, you can get all of the source code for <a href="https://github.com/frenchdog/CreationPlatform101.git">this application on github</a></p>
]]></content:encoded>
			<wfw:commentRss>http://fabricengine.com/2012/10/creation-platform-101-building-a-particle-system-with-creation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Creation Platform 101: The Core Dependency Graph</title>
		<link>http://fabricengine.com/2012/10/test/</link>
		<comments>http://fabricengine.com/2012/10/test/#comments</comments>
		<pubDate>Wed, 17 Oct 2012 17:57:47 +0000</pubDate>
		<dc:creator>Paul Doyle</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://fabricengine.com/?p=3259</guid>
		<description><![CDATA[This series of articles will introduce you to the key concepts behind Creation Platform and step you through the process of building a particle system so that you can see how everything fits together. Note: This tutorial comes with full source code that can be found here: https://github.com/frenchdog/CreationPlatform101.git Why use a Dependency Graph ? The Fabric [...]]]></description>
				<content:encoded><![CDATA[<p dir="ltr"><a title="Creation Platform 101" href="http://fabricengine.com/2012/10/creation-platform-101/">This series of articles</a> will introduce you to the key concepts behind Creation Platform and step you through the process of building a particle system so that you can see how everything fits together.</p>
<p dir="ltr"><em>Note: This tutorial comes with full source code that can be found here:</em><a title="CreationPlatform101" href="https://github.com/frenchdog/CreationPlatform101.git" target="_blank"> https://github.com/frenchdog/CreationPlatform101.git</a></p>
<h2 dir="ltr">Why use a Dependency Graph ?</h2>
<p>The <em>Fabric Core</em> can build a dependency graph (more precisely, a <a href="http://en.wikipedia.org/wiki/Directed_Acyclic_Graph">Directed Acyclic Graph</a>). This graph is used to describe the relationships between data and functions (called operators) &#8211; Creation maintains a separation between data and the operators on those data, which is an important first concept to understand. The operators are written using Fabric&#8217;s high performance Kernel Language (KL), which we will get to later in the article.</p>
<p>Using our example scenario, we will discuss using the dependency graph for working with particles. If you want to move particles using a force, you would define a graph composed of three nodes: a particle node storing the point positions, a time node to store the time step, and a force node. Then you need to specify the dependencies between these nodes. In this example, the particle node is dependent on the time and force nodes.</p>
<p>You may wonder why you should define those dependencies. After all, you could write a python program to move particles, as in this pseudo python code:</p>
<pre class="brush: python; title: ; notranslate">
force = getClosestNeighborPosition()
particlePosition += force * timeStep
</pre>
<p>The problem with this code is that it cannot easily be executed in parallel! The force is dependent upon the previous particle neighbour&#8217;s position, but we cannot guarantee that this previous position is valid, because another thread may have already updated it. This dependency prevents us from executing in parallel, which results in poor performance &#8211; defining dependencies before computing the data is a very important step, since it allows us to execute in parallel. In the Fabric Core, the dependency graph is analyzed at construction-time, and the data is evaluated at run-time. The good news is that a scripting language &#8211; like Python &#8211; is sufficient for describing the dependency graph, as we are not processing heavy data. In contrast, the function implementations are exclusively written using KL. KL is a simple, high-level language used to write high-performance operators. KL allows developers to keep working with Python, using KL only for the performance critical parts of their application. KL uses a similar syntax to JavaScript, but is optimized for performance.</p>
<p>To glue together the data and the operators, a Python class called Binding is used. The Binding class stores the parameter layout of the operator and is accessible from the node that is storing the required data. You can visualize this binding process as follows:</p>
<p style="text-align: center;"><a href="http://fabricengine.com/2012/10/creation-platform-abstracting-the-core-dependency-graph/dg-node-5/" rel="attachment wp-att-3212"><img class="alignnone size-full wp-image-3212" title="DG Node" src="http://fabricengine.com/wp-content/uploads/2012/10/DG-Node4.png" alt="" width="637" height="424" /></a></p>
<p>To build a dependency graph, you always instantiate the following Python classes:  the Dependency Graph Node (DGNode), the Operator, and the Binding.</p>
<ul>
<li>You will use DGNode methods to add a data member or set a dependency with another node. As a DGNode has a list of all its bindings,  you can add a Binding instance to this list. You can imagine this list as a little operator stack for your DGNode, Binding at index 0 of the list being your first operator and so on.</li>
<li>You use Operator methods to get the KL source code you want to use.</li>
<li>You use Binding methods to get the Operator instance object and define the Parameter Layout. The Parameter Layout describes what data member you want to bind to an operator parameter.</li>
</ul>
<h2 dir="ltr">Building a basic particle system:</h2>
<p>To be able to access <em>Fabric Core </em>we instantiate a client. This client can create Python instance objects like the DGNode, the Operator and the Binding.</p>
<pre class="brush: python; title: ; notranslate">
import FabricEngine.Core
FabricCoreClient = FabricEngine.Core.createClient()
</pre>
<p>We instantiate three DGNodes and define their data members.</p>
<pre class="brush: python; title: ; notranslate">
particlesNode = FabricCoreClient.DG.createNode('particles')
particlesNode.addMember(name='pointsCount', typeName='Size', defaultValue=100)
particlesNode.addMember(name='positions', typeName='Vec3[]')

timerNode = FabricCoreClient.DG.createNode('timer')
timerNode.addMember(name='frame', typeName='Integer')
timerNode.addMember(name='rate', typeName='Scalar', defaultValue=60.0)

forcesNode = FabricCoreClient.DG.createNode('forces')
forcesNode.addMember(name='gravity', typeName='Vec3', defaultValue=Vec3(0.0, -9.81, 0.0))
</pre>
<p>In this example we choose to define the particles positions as an array of Vec3. We could instead define a single Vec3 and set the node &#8216;slice count&#8217; to a number greater than one to enable the core to compute over an array of data (“SIMD &#8211; Single Instruction Multiple Data &#8211; parallelization”). Using this feature, the parallelism would be implicit and the KL code simplified. However, using arrays instead of slices gives some advantages: you can define the data set you want to execute in parallel in your KL code. I will explain in more detail these two ways to handle parallelism at the end of this article. For the purposes of the example we will use the explicit parallelization using an array of Vec3, as the python code is shorter and more obvious.</p>
<p>Now we connect the timerNode and the forcesNode to the particlesNode. The dependencyName will be used by the Parameter Layout of the Binding object.</p>
<pre class="brush: python; title: ; notranslate">
particlesNode.setDependency('timer', timerNode)
particlesNode.setDependency('forces', forcesNode)
</pre>
<p>Next, we instantiate the operator that will generate and simulate our positions. This operator gets the KL code that defines the operator function as a string. Here we are using a python File object and its read() method to access an external KL file. The opened file includes the definition of an operator called &#8216;ParticleSystem&#8217;.</p>
<pre class="brush: python; title: ; notranslate">
operator = FabricCoreClient.DG.createOperator(name='ParticleSystem')
operator.setEntryPoint('ParticleSystem')
operator.setSourceCode(open('particlesOperators.kl').read())
</pre>
<p>Now we need to define the relationship between our operator and our data members.<br />
The operator signature in the KL file looks like this :<br />
<span style="color: #800000;">operator ParticlesGenerator(in Integer frame, in Scalar rate, in Size count, io Vec3 positions[], in Vec3 gravity)</span>.<br />
Its first parameter &#8211; called &#8216;frame&#8217; &#8211; will use the eponymous data member of the timerNode and so on.</p>
<pre class="brush: python; title: ; notranslate">
binding = FabricCoreClient.DG.createBinding()
binding.setOperator(operator)
binding.setParameterLayout([
  'timer.frame',
  'timer.rate',
  'self.pointsCount',
  'self.positions',
  'forces.gravity'
])
</pre>
<p>In the Parameter Layout we can use &#8216;self&#8217; to refer to the node that references the Binding object, that is, the particleNode.<br />
We can use &#8216;timer&#8217; or &#8216;forces&#8217; to refer to the timerNode or forcesNode because they are connected to the particleNode.<br />
If you create a dependency called &#8216;forces2&#8242;, then the binding can bind using that binding name, plus the member names. E.g. &#8216;forces2.gravity&#8217;.<br />
To reference the binding we add it to the node bindings list:</p>
<pre class="brush: python; title: ; notranslate">particlesNode.bindings.append(binding)</pre>
<p>Our dependency graph is finished! We could run the python code and it would compile the graph, but it wouldn`t evaluate it. This is because we didn&#8217;t tell the Core which node we would like to evaluate. We need to add a final part that will run our particle simulation:</p>
<pre class="brush: python; title: ; notranslate">
# Simulate 100 frames
for i in range(0, 100):
 timerNode.setData('frame', i)
 particlesNode.evaluate()
 print 'At frame: {0}, first particle position is: {1}'.format(i, particlesNode.getData('positions')[0])
</pre>
<p>The dependency graph is used to define how dirtiness propagates through the graph. We can make a change to a single node, and make many nodes dirty.<br />
if you didn&#8217;t change the time value, the subsequent calls to &#8216;evaluate&#8217; would not do anything, because once the node is &#8216;clean&#8217; it will not re-evaluate. This the a key concept to the &#8216;lazy&#8217; evaluation system. Only nodes that are dirty will be evaluated and cleaned.</p>
<p>Here is the KL code that is run each frame:</p>
<pre class="brush: jscript; title: ; notranslate">
use Vec3, FabricMath;
const Scalar TIMESTEP = 0.01;

function setRandomPosition_perParticle(Size index, Integer offset, io Vec3 positions[])
{
    positions[index].x = mathRandomScalar(index, offset);
    positions[index].y = 10;
    positions[index].z = mathRandomScalar(index, offset + 20);
}

function applyForces_perParticle(Size index, Vec3 gravity, io Vec3 positions[])
{
  positions[index] += gravity * TIMESTEP;
}

operator ParticleSystem(Integer frame, Scalar rate, Size count, io Vec3 positions[], Vec3 gravity)
{
  if(frame == 0)
  {
    positions.resize(count);
    executeParallel( setRandomPosition_perParticle, positions.size, frame, positions );
  }
  executeParallel( applyForces_perParticle, positions.size, gravity, positions );
}
</pre>
<p>We use &#8216;executeParallel()&#8217; to call the same function on every element of our positions array.</p>
<p>Running the python code gives this output:</p>
<p><span style="color: #800000;">At frame: 0 [MT:particles:ParticleSystem] First particle position: {x:+0.465661e-9,y:+9.901900,z:+0.255708}<br />
At frame: 1 [MT:particles:ParticleSystem] First particle position: {x:+0.465661e-9,y:+9.803800,z:+0.255708}<br />
&#8230;<br />
&#8230;</span><br />
<span style="color: #800000;"> At frame: 98 [MT:particles:ParticleSystem] First particle position: {x:+0.465661e-9,y:+0.288099,z:+0.255708}<br />
At frame: 99 [MT:particles:ParticleSystem] First particle position: {x:+0.465661e-9,y:+0.189999,z:+0.255708} </span></p>
<p>Particles are falling down! It is not the most impressive particle simulation :), but we hope it helps you to understand the Core Dependency Graph. Here are the links to the full source code:</p>
<p><span style="color: #333333;"><a href="https://github.com/frenchdog/CreationPlatform101/blob/master/CoreDGApp/ParticleDGNodes.py">Python code for array version</a></span></p>
<p><a href="https://github.com/frenchdog/CreationPlatform101/blob/master/CoreDGApp/particlesOperators.kl">KL code for array version (using executeParallel)</a></p>
<h2 dir="ltr">Slicing nodes or executeParallel ?</h2>
<p>When we instantiated our first DGNodes, we explained that we could use two different approaches for parallel execution. An implicit one called &#8216;slicing&#8217;, and an explicit one using the function &#8216;executeParallel&#8217;. The slicing idea gives the same parallel execution for all the data members of a single DGNode. You specify a number of slices for the node and all of its members share a common array structure. In this KL example, every element in the sliced array (defined using &#8220;&lt;&gt;&#8221;) will be evaluated in parallel.</p>
<pre class="brush: jscript; title: ; notranslate">
operator SlicedOp(Index index, Vec3 positions&lt;&gt;, in Vec3 gravity)
{
  positions[index] += gravity;
}
</pre>
<p>From this code snippet, it might seem that slicing is more elegant than explicit parallelism. However, there are many cases where we would like to use a more explicit system. One reason could be to simplify the dependency graph. Here is a comparison on our simple particle simulation. Using explicit parallel the dependency graph is as follows:</p>
<p><a href="http://fabricengine.com/2012/10/test/array/" rel="attachment wp-att-3296"><img class="alignnone size-full wp-image-3296" title="array" src="http://fabricengine.com/wp-content/uploads/2012/10/array.png" alt="" width="455" height="203" /></a></p>
<p>And using slicing:</p>
<p><a href="http://fabricengine.com/2012/10/test/slicing/" rel="attachment wp-att-3297"><img class="alignnone size-full wp-image-3297" title="slicing" src="http://fabricengine.com/wp-content/uploads/2012/10/slicing.png" alt="" width="535" height="312" /></a></p>
<p>As you can see, we need one more node for the sliced version. The reason, is by slicing a node, we say that the dimension(slice count) of the node defines the dimension of the data. The size of the positions array becomes implicit in the slice count of the node. The &#8216;pointsCount&#8217; is a value of a different dimension, and so can&#8217;t be stored in the sliced node along with the positions. Often we want to combine together data sets of different dimensions, and so slicing becomes too restrictive.<br />
Another advantage of the explicit parallelism is that we can use several executeParallel functions on different arrays of data. Imagine that we want to emit our particles every frame. In this case we must set the initial positions only on the created one, and apply the forces on every one. It can be tricky to do using sliced arrays! Using parallelExecute it is very easy:</p>
<pre class="brush: jscript; title: ; notranslate">
Vec3 newPositions[];
newPositions.resize(count);
executeParallel( setInitialPosition_perPoint, newPositions.size, newPositions );

for(Index i=0; i&lt; newPositions.size; i++)
{
 positions.push(newPositions[i]);
}

executeParallel( applyForces_perPoint, positions.size, positions );
</pre>
<p>But slicing can also be combined with executeParallel ! In this case it can be very useful as you can use it to define instancing. You can easily take your particle system defined using execute parallel and Vec3[] positions, and create 30 different particles systems, by simply increasing the count of the node. Imagine for example, you were building chimney smoke simulation, and then you wanted 100 different chimneys in a village to emit smoke. You can do this easily using a single node, that contains a particle system on each slice, and 100 different slices! You can find more explanation on slicing <a href="http://fabricengine.com/2012/08/using-node-slicing-to-manage-large-scenes/">in this article</a>.</p>
<p>To complete this first part, here is the source code for the sliced version of our particle simualtion: <a href="https://github.com/frenchdog/CreationPlatform101/blob/master/CoreDGApp/ParticlesDGNodesSlices.py">Python code for sliced node version</a> and  <a href="https://github.com/frenchdog/CreationPlatform101/blob/master/CoreDGApp/particlesOperatorSlices.kl">KL code for sliced node</a></p>
<h1><a title="Creation Platform 101: Building a Particle System with Creation" href="http://fabricengine.com/2012/10/creation-platform-101-building-a-particle-system-with-creation/">Part2 Building a Particle System with Creation Platform</a></h1>
]]></content:encoded>
			<wfw:commentRss>http://fabricengine.com/2012/10/test/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
