<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>bl0v3s blog - APL</title>
    <subtitle>bl0v3&#x27;s blog</subtitle>
    <link rel="self" type="application/atom+xml" href="https://bl0v3.com/tags/apl/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://bl0v3.com"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2024-05-02T00:00:00+00:00</updated>
    <id>https://bl0v3.com/tags/apl/atom.xml</id>
    <entry xml:lang="en">
        <title>making use of dyalog APL&#x27;s isolates+futures in the the apl raymarcher</title>
        <published>2024-05-02T00:00:00+00:00</published>
        <updated>2024-05-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            bl0v3
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://bl0v3.com/Blog/bringing-dyalogs-isolates-and-futres-to-the-apl-raymarcher/"/>
        <id>https://bl0v3.com/Blog/bringing-dyalogs-isolates-and-futres-to-the-apl-raymarcher/</id>
        
        <content type="html" xml:base="https://bl0v3.com/Blog/bringing-dyalogs-isolates-and-futres-to-the-apl-raymarcher/">&lt;h1 id=&quot;overcoming-nix-specific-issues-to-get-isolates-and-futures-to-work&quot;&gt;overcoming nix specific issues to get isolates and futures to work&lt;&#x2F;h1&gt;
&lt;p&gt;&lt;strong&gt;(skip to “actual implementation” below if this this isn’t of any interest to you)&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Unlike I initially assumed just importing the isolate workspace on dyalog-apl retrived trough nix’s
nixpkgs ( as I used that to produce these builds in a reproducible&#x2F;declarative fashion) wasn’t
directly feasible as upon loading the workspace I’d get some quite strange errors. Upon further
debugging this issue I came to the conclusion that it was caused by the nix derivation for dyalog-apl
rather than dyalog apl itself.&lt;&#x2F;p&gt;
&lt;p&gt;So after opening an issue and notifying the package maintainer
at &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;NixOS&#x2F;nixpkgs&#x2F;issues&#x2F;316439&quot;&gt;dyalog: isolates (parallel forEach and co) appear to be broken #316439&lt;&#x2F;a&gt; it seems as if they managed to fix it
via &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;NixOS&#x2F;nixpkgs&#x2F;pull&#x2F;316495&quot;&gt;dyalog: also apply patchelf to dyalog.rt #316495&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The issue basically boils down to the following:&lt;&#x2F;p&gt;
&lt;p&gt;As nix stores all binaries&#x2F;libraries in &lt;code&gt;&#x2F;nix&#x2F;store&#x2F;&amp;lt;hash&amp;gt;-&amp;lt;path&amp;gt;&lt;&#x2F;code&gt; packaging binary executables can
be a litty funny at times.  As obtaining the source code for dyalog-apl isn’t possible as for now
were forced to work with the .deb&#x2F;.rpm etc packages they provide. Which is exactly what the nix
expression linked above does.&lt;&#x2F;p&gt;
&lt;p&gt;But just copying the contents of that .deb to &#x2F;bin and &#x2F;lib respectively isn’t all there is to it sadly
as binary packages already have pre defined &lt;a href=&quot;https:&#x2F;&#x2F;en.m.wikipedia.org&#x2F;wiki&#x2F;Executable_and_Linkable_Format&quot;&gt;ELF headers&lt;&#x2F;a&gt; these make assumptions about the names and locations of the library components to be loaded
upon executing the elf by the linux kernel.&lt;&#x2F;p&gt;
&lt;p&gt;like mentioned in the issue the maintainer forgot to also add ncurses to &lt;code&gt;dyalog.rt&lt;&#x2F;code&gt;
luckily as the elf specification is simple enough&lt;&#x2F;p&gt;
&lt;img class=&quot;&quot;src=&quot;https:&amp;#x2F;&amp;#x2F;raw.githubusercontent.com&amp;#x2F;corkami&amp;#x2F;pics&amp;#x2F;master&amp;#x2F;binary&amp;#x2F;elf101&amp;#x2F;elf101.svg&quot;&#x2F;&gt;
&lt;p&gt;to alter using tools such as &lt;code&gt;patchelf&lt;&#x2F;code&gt;, which is very frequently seen when packaging binary packages
for nix&#x2F;nixos.&lt;&#x2F;p&gt;
&lt;p&gt;Thus everything required to do was changing&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;patchelf&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-parameter z-begin z-shell&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;dyalogHome&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-parameter z-end z-shell&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;dyalog&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;add-needed&lt;&#x2F;span&gt; libncurses.so&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;to&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-keyword z-control z-loop z-for z-shell&quot;&gt;for&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-for z-shell&quot;&gt; exec &lt;span class=&quot;z-keyword z-control z-in z-shell&quot;&gt;in&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;dyalog&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;dyalog.rt&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-continue z-shell&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-loop z-do z-shell&quot;&gt;do&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;     &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;patchelf&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-parameter z-begin z-shell&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;dyalogHome&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-parameter z-end z-shell&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;exec&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;add-needed&lt;&#x2F;span&gt; libncurses.so&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-keyword z-control z-loop z-end z-shell&quot;&gt;done&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;within the nix expression. Which the maintainer did an awesome job of figuring out &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;NixOS&#x2F;nixpkgs&#x2F;pull&#x2F;316495&#x2F;commits&#x2F;0ea7fe9f11803bea5fd9f6b2ecd96fd96b0731e7&quot;&gt;see&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Thus using the package with the previous expression running ldd would result in&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;linux-vdso.so.1 (0x00007ffff7fc6000)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;libm.so.6 =&amp;gt; &#x2F;nix&#x2F;store&#x2F;k7zgvzp2r31zkg9xqgjim7mbknryv6bs-glibc-2.39-52&#x2F;lib&#x2F;libm.so.6 (0x00007ffff7edd000)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;libpthread.so.0 =&amp;gt; &#x2F;nix&#x2F;store&#x2F;k7zgvzp2r31zkg9xqgjim7mbknryv6bs-glibc-2.39-52&#x2F;lib&#x2F;libpthread.so.0 (0x00007ffff7ed8000)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;libdl.so.2 =&amp;gt; &#x2F;nix&#x2F;store&#x2F;k7zgvzp2r31zkg9xqgjim7mbknryv6bs-glibc-2.39-52&#x2F;lib&#x2F;libdl.so.2 (0x00007ffff7ed3000)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;libc.so.6 =&amp;gt; &#x2F;nix&#x2F;store&#x2F;k7zgvzp2r31zkg9xqgjim7mbknryv6bs-glibc-2.39-52&#x2F;lib&#x2F;libc.so.6 (0x00007ffff7213000)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&#x2F;nix&#x2F;store&#x2F;k7zgvzp2r31zkg9xqgjim7mbknryv6bs-glibc-2.39-52&#x2F;lib&#x2F;ld-linux-x86-64.so.2 =&amp;gt; &#x2F;nix&#x2F;store&#x2F;k7zgvzp2r31zkg9xqgjim7mbknryv6bs-glibc-2.39-52&#x2F;lib64&#x2F;ld-linux-x86-64.so.2 (0x00007ffff7fc8000)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;while using the fixed drv with ncurses being added to the elf header would result in&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;linux-vdso.so.1 (0x00007ffff7fc6000)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;libncurses.so =&amp;gt; &#x2F;nix&#x2F;store&#x2F;zcjy82jk8i8y1cvvzaadj5wiz41gvp53-ncurses-abi5-compat-6.4&#x2F;lib&#x2F;libncurses.so (0x00007ffff7f58000)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;libm.so.6 =&amp;gt; &#x2F;nix&#x2F;store&#x2F;k7zgvzp2r31zkg9xqgjim7mbknryv6bs-glibc-2.39-52&#x2F;lib&#x2F;libm.so.6 (0x00007ffff7e75000)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;libpthread.so.0 =&amp;gt; &#x2F;nix&#x2F;store&#x2F;k7zgvzp2r31zkg9xqgjim7mbknryv6bs-glibc-2.39-52&#x2F;lib&#x2F;libpthread.so.0 (0x00007ffff7e70000)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;libdl.so.2 =&amp;gt; &#x2F;nix&#x2F;store&#x2F;k7zgvzp2r31zkg9xqgjim7mbknryv6bs-glibc-2.39-52&#x2F;lib&#x2F;libdl.so.2 (0x00007ffff7e6b000)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;libc.so.6 =&amp;gt; &#x2F;nix&#x2F;store&#x2F;k7zgvzp2r31zkg9xqgjim7mbknryv6bs-glibc-2.39-52&#x2F;lib&#x2F;libc.so.6 (0x00007ffff7213000)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&#x2F;nix&#x2F;store&#x2F;k7zgvzp2r31zkg9xqgjim7mbknryv6bs-glibc-2.39-52&#x2F;lib&#x2F;ld-linux-x86-64.so.2 =&amp;gt; &#x2F;nix&#x2F;store&#x2F;k7zgvzp2r31zkg9xqgjim7mbknryv6bs-glibc-2.39-52&#x2F;lib64&#x2F;ld-linux-x86-64.so.2 (0x00007ffff7fc8000)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;note &lt;code&gt;libncurses.so =&amp;gt; &#x2F;nix&#x2F;store&#x2F;zcjy82jk8i8y1cvvzaadj5wiz41gvp53-ncurses-abi5-compat-6.4&#x2F;lib&#x2F;libncurses.so (0x00007ffff7f58000)&lt;&#x2F;code&gt; being present now after applying the fix&lt;&#x2F;p&gt;
&lt;p&gt;So until that PR&#x2F;commit is merged into nixpkgs I’d have to specify:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;nix&quot; class=&quot;language-nix z-code&quot;&gt;&lt;code class=&quot;language-nix&quot; data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;inputs&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;nixpkgs&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-attrset-or-function z-nix&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;      &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;url&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;https:&#x2F;&#x2F;github.com&#x2F;TomaSajt&#x2F;nixpkgs.git&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;      &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;git&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;      &lt;span class=&quot;z-entity z-other z-attribute-name z-multipart z-nix&quot;&gt;rev&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bind z-nix&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-double z-start z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;0ea7fe9f11803bea5fd9f6b2ecd96fd96b0731e7&lt;span class=&quot;z-punctuation z-definition z-string z-double z-end z-nix&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;    &lt;span class=&quot;z-comment z-line z-number-sign z-nix&quot;&gt;# other inputs ...&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;  &lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-bind z-nix&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-nix&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-attrset z-nix&quot;&gt;}&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;within my flake.nix expression used to build this project. If you aren’t using nix but the rpm&#x2F;deb
package youd of course not have to do this.&lt;&#x2F;p&gt;
&lt;p&gt;Another approach of solving this issue would be using &lt;a href=&quot;https:&#x2F;&#x2F;ryantm.github.io&#x2F;nixpkgs&#x2F;builders&#x2F;special&#x2F;fhs-environments&#x2F;&quot;&gt;buildFHSEnv&lt;&#x2F;a&gt;
which I would have done if me or the maintainers couldn’t figure out how to fix this
in time.&lt;&#x2F;p&gt;
&lt;p&gt;As &lt;em&gt;buildFHS env uses Linux’ namespaces feature to create temporary lightweight environments which are destroyed after all child processes exit, without requiring elevated privileges. It works similar to containerisation technology such as Docker or FlatPak but provides no security-relevant separation from the host system&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;this implies the presence of a namespace enabled linux kernel which would break nix’s excellent
macos&#x2F;darwin support as well as nix on non namespace enabled linux systems. So in order to keep
the majority of nixpkgs functional on macos and non-nixos systems
&lt;em&gt;(by the way nix is availible in the debian&#x2F;arch repos by default)&lt;&#x2F;em&gt;  patchelf is generally to be favored.
But in especially nasty cases such as where precompiled (e.g nonfree packages such as steam lets say)
packages are expecting certain binaries or files in general to be present in &lt;strong&gt;&#x2F;sbin&#x2F;&lt;&#x2F;strong&gt; , &lt;strong&gt;&#x2F;bin&#x2F;&lt;&#x2F;strong&gt; or
&lt;strong&gt;&#x2F;usr&#x2F;bin&lt;&#x2F;strong&gt; and the files are sourced at runtime rather than via the elf header upon program load.
buildFHS would have to be used as thats a better approach than trying to binary-patch the hardcoded
references within the compiled software.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;actual-implementation&quot;&gt;actual implementation&lt;&#x2F;h1&gt;
&lt;p&gt;Since &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bolives-hax&#x2F;apl-raymarcher&#x2F;commit&#x2F;ddde091fa2cb4c635cc6a1e39a2f4f6183852317&quot;&gt;this commit&lt;&#x2F;a&gt; multithreading is now availible&lt;&#x2F;p&gt;
&lt;p&gt;While at the time of writing this the amount of theads is hardcoded via &lt;code&gt;threads←4&lt;&#x2F;code&gt; in flake.nix but you are free to changing
the amount of threads by either altering the &lt;code&gt;raymarcher.apl&lt;&#x2F;code&gt; file or the flake.nix file accordingly (see flake.nix to see what variables need to be applied).
Thus rendering with much more than 4 threads is totally feasible and it does seem to be able to truly utilize all resources given to it perfectly fine.&lt;&#x2F;p&gt;
&lt;p&gt;See (rendering in 4K):&lt;&#x2F;p&gt;
&lt;img class=&quot;&quot;src=&quot;https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;bolives-hax&amp;#x2F;apl-raymarcher&amp;#x2F;blob&amp;#x2F;master&amp;#x2F;multithread-showcase.jpg?raw=true&quot;&#x2F;&gt;
&lt;p&gt;(TODO actually explain how this was pulled off. Until then check &lt;code&gt;raymarcher.apl&lt;&#x2F;code&gt;’s comments that were added in the commit linked above&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Raymarching meets dyalog APL</title>
        <published>2024-04-28T00:00:00+00:00</published>
        <updated>2024-04-28T00:00:00+00:00</updated>
        
        <author>
          <name>
            bl0v3
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://bl0v3.com/Blog/raymarching-in-dyalog-apl/"/>
        <id>https://bl0v3.com/Blog/raymarching-in-dyalog-apl/</id>
        
        <content type="html" xml:base="https://bl0v3.com/Blog/raymarching-in-dyalog-apl/">&lt;img class=&quot;&quot;src=&quot;https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;bolives-hax&amp;#x2F;apl-raymarcher&amp;#x2F;blob&amp;#x2F;master&amp;#x2F;preview_final.png?raw=true&quot;&#x2F;&gt;&lt;h1 id=&quot;code&quot;&gt;code&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;source-code&quot;&gt;source code&lt;&#x2F;h2&gt;
&lt;p&gt;As for now I only provide build expression through nix which
alongside the source-code are located at &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bolives-hax&#x2F;apl-raymarcher&quot;&gt;this github repository&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;&#x2F;strong&gt;: Since &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bolives-hax&#x2F;apl-raymarcher&#x2F;commit&#x2F;ddde091fa2cb4c635cc6a1e39a2f4f6183852317&quot;&gt;this commit&#x2F;relase&lt;&#x2F;a&gt;
multithreading is now officially supported. Though this page was written before I added support for that&lt;&#x2F;p&gt;
&lt;h2 id=&quot;running-it-yourself&quot;&gt;running it yourself&lt;&#x2F;h2&gt;
&lt;p&gt;Currently the build targets&#x2F;instructions are supplied via (&lt;strong&gt;nix&lt;&#x2F;strong&gt;)[https:&#x2F;&#x2F;nixos.org&#x2F;]
as it provides a quick, declarative and reproducible way to build this project but the
build instructions can easily be derived from the flake.nix file located in the root directory
of the repository linked above.&lt;&#x2F;p&gt;
&lt;p&gt;Thus:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;running-under-nix&quot;&gt;running under nix&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;nix&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; run github:bolives-hax&#x2F;apl-raymarcher#pngRunner&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;no-write-lock-file&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; output will we placed in cwd as rendering.png&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;(take a look at the repositories README.md or flake.nix file for further targets&#x2F;runners)&lt;&#x2F;p&gt;
&lt;h1 id=&quot;implementation-details&quot;&gt;implementation details&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;so-how-does-it-work&quot;&gt;so how does it work?&lt;&#x2F;h2&gt;
&lt;p&gt;With ray marching works pretty similar to ray tracing, but instead of checking
if our ray intersects with object’s exposed surface through the means of algorithms
such as &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm&quot;&gt;the Möller–Trumbore intersection algorithm&lt;&#x2F;a&gt;. We instead use something called &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Signed_distance_function&quot;&gt;signed distance functions&lt;&#x2F;a&gt; or short “SDF” ’s. Essentially signed distance functions&#x2F;SDFs are functions taking a given point in space &lt;code&gt;p&lt;&#x2F;code&gt; as their input parameter returning the distance from the given point &lt;code&gt;p&lt;&#x2F;code&gt; and the geometry it defines.&lt;&#x2F;p&gt;
&lt;p&gt;For example the SDF for a sphere would look something like this (in GLSL)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;glsl&quot; class=&quot;language-glsl z-code&quot;&gt;&lt;code class=&quot;language-glsl&quot; data-lang=&quot;glsl&quot;&gt;&lt;span class=&quot;z-source z-glsl&quot;&gt;&lt;span class=&quot;z-storage z-type z-glsl&quot;&gt;float&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-glsl&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-glsl&quot;&gt;sphereSDF&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-glsl&quot;&gt;&lt;span class=&quot;z-meta z-group z-glsl&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-glsl&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-glsl&quot;&gt;&lt;span class=&quot;z-meta z-group z-glsl&quot;&gt;&lt;span class=&quot;z-storage z-type z-glsl&quot;&gt;vec3&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-glsl&quot;&gt;p&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-glsl&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-glsl&quot;&gt;float&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-glsl&quot;&gt;radius&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-glsl&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-glsl&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-glsl&quot;&gt;&lt;span class=&quot;z-meta z-block z-glsl&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-glsl&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-glsl&quot;&gt;&lt;span class=&quot;z-meta z-block z-glsl&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-glsl&quot;&gt;&lt;span class=&quot;z-meta z-function z-glsl&quot;&gt;&lt;span class=&quot;z-meta z-block z-glsl&quot;&gt;    # &lt;span class=&quot;z-meta z-function-call z-glsl&quot;&gt;&lt;span class=&quot;z-support z-function z-glsl&quot;&gt;length&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-glsl&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-glsl&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-glsl&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-glsl&quot;&gt;&lt;span class=&quot;z-meta z-group z-glsl&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-glsl&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; gets the length of its arguments vector
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-glsl&quot;&gt;&lt;span class=&quot;z-meta z-function z-glsl&quot;&gt;&lt;span class=&quot;z-meta z-block z-glsl&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-glsl&quot;&gt;&lt;span class=&quot;z-support z-function z-glsl&quot;&gt;length&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-glsl&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-glsl&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-glsl&quot;&gt;&lt;span class=&quot;z-meta z-group z-glsl&quot;&gt;p&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-glsl&quot;&gt;&lt;span class=&quot;z-meta z-group z-glsl&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-glsl&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-glsl&quot;&gt;-&lt;&#x2F;span&gt; radius&lt;span class=&quot;z-punctuation z-terminator z-glsl&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-glsl&quot;&gt;&lt;span class=&quot;z-meta z-function z-glsl&quot;&gt;&lt;span class=&quot;z-meta z-block z-glsl&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-glsl&quot;&gt;&lt;span class=&quot;z-meta z-block z-glsl&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-glsl&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Essentially taking the length of a point spanned from one point to another. As in some point along the ray originating from our camera subtracted by the radius of a sphere. Tells us how far away that sphere (with the given radius) is from the supplied point (passed as &lt;em&gt;&lt;strong&gt;vec3 p&lt;&#x2F;strong&gt;&lt;&#x2F;em&gt; in this example).&lt;&#x2F;p&gt;
&lt;img class=&quot;&quot;src=&quot;https:&amp;#x2F;&amp;#x2F;ch-st.de&amp;#x2F;assets&amp;#x2F;posts&amp;#x2F;its-ray-marching-march&amp;#x2F;spheresdf.svg&quot;&#x2F;&gt;
&lt;p&gt;A possible implementation of said SDF in APL may look like this:  (Taken from my implementation):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;apl&quot; class=&quot;language-apl z-code&quot;&gt;&lt;code class=&quot;language-apl&quot; data-lang=&quot;apl&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;ball_sdf←{  (length ⍵) - ⍺ }
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;with the &lt;code&gt;length&lt;&#x2F;code&gt; function being supplied through:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;apl&quot; class=&quot;language-apl z-code&quot;&gt;&lt;code class=&quot;language-apl&quot; data-lang=&quot;apl&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;⍝ ⍺ =2 would mean the squareroot
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;sqrt←{⍵*÷⍺}
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;length←{2 sqrt (+&#x2F;{⍵*2}¨⍵)}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;&#x2F;strong&gt; As its called &lt;strong&gt;signed&lt;&#x2F;strong&gt; distance function instead of just &lt;strong&gt;distance function&lt;&#x2F;strong&gt; or &lt;strong&gt;usigned&lt;&#x2F;strong&gt;
the values returned make use of (signed number representation)[https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Signed_number_representations].&lt;&#x2F;p&gt;
&lt;p&gt;What this means in practice is assuming lets say we’d run it against a point contained within the sphere defined
by the function above:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;apl&quot; class=&quot;language-apl z-code&quot;&gt;&lt;code class=&quot;language-apl&quot; data-lang=&quot;apl&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;(0.5) ball_sdf((0)(0)(0))
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;we’d get a negative return value of &lt;code&gt;¯0.5&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;using a point such as &lt;code&gt;(0.28 0.28 0.28)&lt;&#x2F;code&gt; instead which is pretty much on the edge
provided by the diameter&#x2F;radius of said sphere like:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;apl&quot; class=&quot;language-apl z-code&quot;&gt;&lt;code class=&quot;language-apl&quot; data-lang=&quot;apl&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;      (0.5) ball_sdf((0.28)(0.28)(0.28))
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;wed get &lt;code&gt;¯0.01502577388&lt;&#x2F;code&gt; as the length of &lt;code&gt;(0.28 0.28 0.28)&lt;&#x2F;code&gt; which roughly equates to &lt;code&gt;0.48497...&lt;&#x2F;code&gt;.
What we can essentially derive from that information is:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;if &lt;code&gt;sdf(p)&lt;&#x2F;code&gt; is positive, p lays outside of &lt;code&gt;sdf&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;if &lt;code&gt;sdf(p)&lt;&#x2F;code&gt; is negative, p lays within &lt;code&gt;sdf&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;if &lt;code&gt;sdf(p)&lt;&#x2F;code&gt; is very close to +-0 as in lets say &lt;code&gt;sdf(p) &amp;lt; 0.0001&lt;&#x2F;code&gt; &lt;code&gt;p&lt;&#x2F;code&gt; lays on the edge or within &lt;code&gt;sdf()&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Ok but how do we go from having a SDF to actually approximating where and if  object is hit=visible?&lt;&#x2F;p&gt;
&lt;p&gt;Luckily that is quite simple to do. First we need to define some variables though&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Assuming the function res supplies the horizontal and vertical resolutions as&lt;&#x2F;em&gt; &lt;strong&gt;(x y)&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;apl&quot; class=&quot;language-apl z-code&quot;&gt;&lt;code class=&quot;language-apl&quot; data-lang=&quot;apl&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;res←↑(get_res drawer ( 0 0 ))[2]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;xres←(res)[1] ⋄ yres←(res)[2] 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;cam_origin←(0 0 ¯1)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As we now have the dimensions of image&#x2F;frame we intend to render. We map each pixel onto a 2 dimensional plane
to then cast a ray through each respectively mapped pixel coordinate &lt;code&gt;(x,y)&lt;&#x2F;code&gt;. There are various ways to represent our
pixel&#x2F;plane-coordinate mapping. In my approach I first span a map going from &lt;strong&gt;&lt;code&gt;(0,0)&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; to &lt;strong&gt;&lt;code&gt;(1,1)&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;
and offset that to  &lt;strong&gt;&lt;code&gt;(-0.5,-0.5)&lt;&#x2F;code&gt; to &lt;code&gt;(0.5) (0.5)&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; as I prefer that notation.&lt;&#x2F;p&gt;
&lt;p&gt;One way of implementing this would be through&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;apl&quot; class=&quot;language-apl z-code&quot;&gt;&lt;code class=&quot;language-apl&quot; data-lang=&quot;apl&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;xy←{((⍳(xres))-1)⍵}¨((⍳(yres))-1)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;_uv←{(⊃⍵[1]÷xres) (⍵[2]÷yres)}¨xy
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;uv←_uv-0.5
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This illustration further outlines the process underwent&lt;&#x2F;p&gt;
&lt;img class=&quot;&quot;src=&quot;https:&amp;#x2F;&amp;#x2F;varun.ca&amp;#x2F;static&amp;#x2F;ray-march-41bd80ce90cdf1dde6084381abf07d6f.svg&quot;&#x2F;&gt;
&lt;p&gt;Before we can then run our SDF’s against the rays cast through the 2d pixel&#x2F;plane-coordinate mapping
one should also apply the so called &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Aspect_ratio_(image)&quot;&gt;aspect ratio&lt;&#x2F;a&gt; through:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;apl&quot; class=&quot;language-apl z-code&quot;&gt;&lt;code class=&quot;language-apl&quot; data-lang=&quot;apl&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;uv←{⊃((⍵[1] ÷ (xres ÷ yres)) ⍵[2])}¨uv
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;uv_vecs ← ⊃,&#x2F;{y←⍵[2] ⋄ {⍵ (-y)}¨(⊃⍵[1]) }¨uv
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With the pixel&#x2F;plane-coordinate mapping in place and the aspect ratio being corrected. Generating rays is as simple as:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;apl&quot; class=&quot;language-apl z-code&quot;&gt;&lt;code class=&quot;language-apl&quot; data-lang=&quot;apl&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	x←⍵[1]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	y←⍵[2]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	cam_dir←norm x y 1
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    rgb cam_dir t 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}¨uv_vecs
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The code above would emit an array of normalized directional vectors with the respective &lt;code&gt;(x y)&lt;&#x2F;code&gt; pixel&#x2F;plane-coordinate mapping being apply the the vectors &lt;code&gt;x&lt;&#x2F;code&gt; and &lt;code&gt;y&lt;&#x2F;code&gt; directional components. This along with the camera origin
would provide the basis for our camera model.&lt;&#x2F;p&gt;
&lt;p&gt;In my renderer the function &lt;strong&gt;rgba&lt;&#x2F;strong&gt; lays the basis to converting ray vectors to actual color values.&lt;&#x2F;p&gt;
&lt;p&gt;Now casting the ray is done using the abstract below&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;apl&quot; class=&quot;language-apl z-code&quot;&gt;&lt;code class=&quot;language-apl&quot; data-lang=&quot;apl&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;rgb cam_dir t 
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;where &lt;code&gt;cam_dir&lt;&#x2F;code&gt; is the vector with the directional components described above and &lt;code&gt;t&lt;&#x2F;code&gt; denoting time &lt;em&gt;(while not implemented yet one could reference the &lt;code&gt;t&lt;&#x2F;code&gt; variable if one wanted to render an animated scene)&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Though you may ask yourself: why is it called ray marching? Like where is the actual &lt;em&gt;“marching”&lt;&#x2F;em&gt; taking place? And why do we
even need to march in the first place? Isn’t using that SDF by itself enough?&lt;&#x2F;p&gt;
&lt;p&gt;Well essentially what would happen if you had lets say 2+ objects and the ray would
come quite close to one object initially but then still pass by. Not actually intersecting the objects surface and maybe hit another object. As the SDF would still return the distance of the closest object (See below)&lt;&#x2F;p&gt;
&lt;img class=&quot;&quot;src=&quot;https:&amp;#x2F;&amp;#x2F;www.tylerbovenzi.com&amp;#x2F;RayMarch&amp;#x2F;Assets&amp;#x2F;figure3.png&quot;&#x2F;&gt;
&lt;p&gt;(TODO add a better ilustration)&lt;&#x2F;p&gt;
&lt;p&gt;this wouldn’t tell us too much. The SDF by itself doesn’t respect the rays direction but just provides a mere distance
estimate. As you can see the distance it determines can represented in a fashion resembling the radius of a sphere. Meaning
it only tells us the distance from one point to another point but not if it actually lays along a ray.&lt;&#x2F;p&gt;
&lt;p&gt;In order to accommodate for this issue. We essentially to approach the point we plan intersect in a step-wise manner. The smaller the lowest possible distance grows, the smaller further steps undertaken would be. If the distance
is approaching 0 &lt;em&gt;(getting very close to it)&lt;&#x2F;em&gt; . We’d register that as a hit. Otherwise we would step on until either the max step count is reached or the maximum distance is exceeded.&lt;&#x2F;p&gt;
&lt;p&gt;The marching function is called from the &lt;code&gt;rbg&lt;&#x2F;code&gt; function described above, at the time of writing this it looks like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;apl&quot; class=&quot;language-apl z-code&quot;&gt;&lt;code class=&quot;language-apl&quot; data-lang=&quot;apl&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;⍝ ⍵ = [ cam_dir time bg ]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;rgb←{
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    cam_dir←⊃⍵[1]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	time←⊃⍵[2]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	d←(( 0 cam_origin  cam_dir 35 100) march 0)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	hit←d[1]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	⍝ 	phong ( total_dist , ro , rd , obj)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	hit: phong ((d[2]) cam_origin cam_dir (d[3]))  
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	⍝ not hit (render background)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	(sky cam_dir[1] (0 ⌈ ((cam_dir[2])+0.12)))
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Essentially  &lt;code&gt;d←(( 0 cam_origin  cam_dir 35) march 0)&lt;&#x2F;code&gt; is where the magic happens. Our march function will march
along &lt;code&gt;cam_dir&lt;&#x2F;code&gt; vector, starting from &lt;code&gt;cam_origin&lt;&#x2F;code&gt;. The &lt;code&gt;35&lt;&#x2F;code&gt; denotes the maximum of &lt;code&gt;35&lt;&#x2F;code&gt; steps which will be taken. Of course that can be adjusted. For example rendering reflections should get away using a lower maximum step count, as less precision is needed there I figured.  &lt;code&gt;100&lt;&#x2F;code&gt; denotes  the maximum distance objects can have from the ray origin &lt;em&gt;(camera)&lt;&#x2F;em&gt; . So we render objects up until the vector length of &lt;code&gt;100.0&lt;&#x2F;code&gt; from the camera. While technically not needed, if we omitted this wed always take &lt;code&gt;35&lt;&#x2F;code&gt; or whatever out max step count is set to until giving up. This reduces the amount of unnecessary computations needed. The first argument of &lt;code&gt;march&lt;&#x2F;code&gt; is the distance stepped so far. We initialize this with 0, as march internally calls itself in a self referencing fashion with the distance value increasing when its supplied as the first parameter in further self referencing calls to &lt;code&gt;march&lt;&#x2F;code&gt;. The argument on the right most side of march is the &lt;code&gt;stepcount&lt;&#x2F;code&gt;. We also initialize this with 0 as march will every time it calls itself increment that by one.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;march&lt;&#x2F;code&gt; first return value returns either &lt;code&gt;0&lt;&#x2F;code&gt; or &lt;code&gt;1&lt;&#x2F;code&gt; as in &lt;code&gt;(hit,...)&lt;&#x2F;code&gt; which is inspected before accessing the further
return values, such as the distance &lt;code&gt;d[2]&lt;&#x2F;code&gt; or the respective id of the object hit &lt;code&gt;d[3]&lt;&#x2F;code&gt;. Further processing of &lt;code&gt;march&lt;&#x2F;code&gt;’s
return values is bound to that first &lt;code&gt;hit&lt;&#x2F;code&gt; value. Since if march never hit anything, we couldn’t return anything in these fields
and thus it would be pointless to work with them.&lt;&#x2F;p&gt;
&lt;p&gt;Assuming &lt;code&gt;hit=1&lt;&#x2F;code&gt; as in &lt;strong&gt;true&lt;&#x2F;strong&gt; wed call the &lt;code&gt;phong&lt;&#x2F;code&gt; function which would apply &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Phong_shading&quot;&gt;the phong shading model&lt;&#x2F;a&gt; taking as its last parameter the id of the object hit. As knowing that we can from within &lt;code&gt;phong&lt;&#x2F;code&gt; apply different “material” properties by using different light absorption&#x2F;reflection attributes in accordance with the &lt;em&gt;phong shading model&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;If nothing was hit the &lt;code&gt;sky&lt;&#x2F;code&gt; function will be called returning the &lt;strong&gt;r g b&lt;&#x2F;strong&gt; components of the background for the given point.&lt;&#x2F;p&gt;
&lt;p&gt;Now lets dissect the march function to gain a better understanding of it:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;apl&quot; class=&quot;language-apl z-code&quot;&gt;&lt;code class=&quot;language-apl&quot; data-lang=&quot;apl&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;⍝ ⍺ = [ total_dist , ro , rd , max_steps, max_dist ]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;⍝ ⍵ = stepcount
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;march←{
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	total_dist ← ⍺[1]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	ro ← ⊃⍺[2] 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	rd ← ⊃⍺[3]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	max_steps ← ⊃⍺[4]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	max_dist ← ⊃⍺[5]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	r ← sdf ( ro + rd × total_dist )
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	dist ← r[1]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	obj  ← r[2]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	⍝ if we exceeded the maximum amount of steps return 0
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	⍝ AND we exceeded the maximum distance from the ray origin=( eg cam pos&#x2F;point of reflection) return 0
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	⍝ TODO use dist to simulate fog  by adding some fog color value based on the distance
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	⍵&amp;lt;max_steps ^ dist &amp;lt; max_dist: {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;		dist &amp;lt; epsi: (1 (dist + total_dist) obj )
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;		( (dist + total_dist) ro rd max_steps max_dist) march ⍵
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	} ⍵+1
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	(0 0)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I believe the abstract is pretty self explanatory but in essence &lt;code&gt;r ← sdf ( ro + rd × total_dist )&lt;&#x2F;code&gt; is of most
interest. All &lt;em&gt;SDF’s&lt;&#x2F;em&gt; at least take one parameter &lt;code&gt;p&lt;&#x2F;code&gt; which denotes the point in space the signed distance function
returns the respective &lt;em&gt;distance&lt;&#x2F;em&gt; to. In order to &lt;em&gt;“march”&lt;&#x2F;em&gt; we must progress our directional vector &lt;code&gt;rd&lt;&#x2F;code&gt; derived
through the pixel mapping above by the &lt;code&gt;total_dist&lt;&#x2F;code&gt;  factor to get the current distance to run our intersection-range
checks against. This needs to be added to the camera origin positional vector &lt;code&gt;ro&lt;&#x2F;code&gt;. We could also leave &lt;code&gt;ro&lt;&#x2F;code&gt; out but then our camera would be restricted to being located at &lt;code&gt;0 0 0&lt;&#x2F;code&gt;. But to deliver more flexibility here and as the march function is used in other places within this program
&lt;em&gt;(for example for marching along reflection rays which start from the surface we reflected from)&lt;&#x2F;em&gt; . So its generally
better to add &lt;code&gt;ro&lt;&#x2F;code&gt; here.&lt;&#x2F;p&gt;
&lt;p&gt;We could for example set &lt;code&gt;r&lt;&#x2F;code&gt; to the &lt;code&gt;ball_sdf←{  (length ⍵) - ⍺ }&lt;&#x2F;code&gt; function as showcased early on in this article.
&lt;code&gt;⍵&lt;&#x2F;code&gt;  denotes the point &lt;code&gt;p&lt;&#x2F;code&gt; in this case  &lt;code&gt;ro + rd × total_dist&lt;&#x2F;code&gt;  while &lt;code&gt;⍺&lt;&#x2F;code&gt; represents the radius of the sphere.
Were not limited to a single sphere sdf. Of course one could also combine multiple sdf’s through use of the &lt;code&gt;⌊&lt;&#x2F;code&gt; &amp;gt; &lt;strong&gt;minimum&lt;&#x2F;strong&gt;  operator.&lt;&#x2F;p&gt;
&lt;p&gt;For example showing 2 spheres. One in the center of our scene and one located at &lt;code&gt;y=+1&lt;&#x2F;code&gt; through defining&#x2F;calling:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;apl&quot; class=&quot;language-apl z-code&quot;&gt;&lt;code class=&quot;language-apl&quot; data-lang=&quot;apl&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;(ball_sdf (p - (0 0 0)) ⌊ (ball_sdf (p - (0 1 0))
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This works as it would return the distance to the sphere closest to us. &lt;code&gt;(-sdf1) ⌈ (sdf2)&lt;&#x2F;code&gt; could be used
to carve out the first geometry defined by the first sdf from the second one &lt;strong&gt;NOTE: this “-” sign is required here&lt;&#x2F;strong&gt;. Likewise
using &lt;code&gt; (sdf1) ⌈ (sdf2)&lt;&#x2F;code&gt; &lt;strong&gt;max&lt;&#x2F;strong&gt; would  instead return only the points where &lt;code&gt;sdf1&lt;&#x2F;code&gt; intersects with &lt;code&gt;sdf2&lt;&#x2F;code&gt;. There are lots
of tricks that can be used when working with signed distance functions. But it should already be clear that even with
just min and max and + and - one can compose some pretty complex geometry.&lt;&#x2F;p&gt;
&lt;p&gt;Now I will focus on the call to the &lt;code&gt;phong&lt;&#x2F;code&gt; function seen before in &lt;code&gt;rgb&lt;&#x2F;code&gt;. &lt;code&gt;rgb&lt;&#x2F;code&gt; has the section:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;apl&quot; class=&quot;language-apl z-code&quot;&gt;&lt;code class=&quot;language-apl&quot; data-lang=&quot;apl&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;hit: phong ((d[2]) cam_origin cam_dir (d[3]))  
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;which essentially runs &lt;code&gt;phong&lt;&#x2F;code&gt; with the parameters&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;apl&quot; class=&quot;language-apl z-code&quot;&gt;&lt;code class=&quot;language-apl&quot; data-lang=&quot;apl&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;⍝ ⍵ = [ total_dist , ro , rd , obj]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The start of &lt;code&gt;phong&lt;&#x2F;code&gt; is structured like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;apl&quot; class=&quot;language-apl z-code&quot;&gt;&lt;code class=&quot;language-apl&quot; data-lang=&quot;apl&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;⍝ ⍵ = [ total_dist , ro , rd , obj]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;phong←{
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	total_dist←⊃⍵[1]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	ro←⊃⍵[2]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	rd←⊃⍵[3]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	obj←⍵[4]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	p←ro + rd × total_dist
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	l1←{
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;		ambient_color←checkers_ball p
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;		diffuse_color←0.5 0.5 0.5
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;		specular_color←0.1 0.1 0.1
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;		alpha←0.7
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;		light_intensity←⍵
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;		ambient_color diffuse_color specular_color alpha light_intensity 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	} 0.5
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    ⍝ ... further lights
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	lightPos←3 3 0 ⍝ hardcoded here but could ofc be passed  via ⍵[5]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;l1&lt;&#x2F;code&gt; defines a light locally. In my case &lt;code&gt;phong&lt;&#x2F;code&gt; defines &lt;code&gt;l1&lt;&#x2F;code&gt; - &lt;code&gt;l7&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Instead of trying myself at explaining what&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;apl&quot; class=&quot;language-apl z-code&quot;&gt;&lt;code class=&quot;language-apl&quot; data-lang=&quot;apl&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;ambient_color←checkers_ball p
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;diffuse_color←0.5 0.5 0.5
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;specular_color←0.1 0.1 0.1
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;does. I will just include a picture that gets the point across&lt;&#x2F;p&gt;
&lt;img class=&quot;&quot;src=&quot;https:&amp;#x2F;&amp;#x2F;upload.wikimedia.org&amp;#x2F;wikipedia&amp;#x2F;commons&amp;#x2F;thumb&amp;#x2F;6&amp;#x2F;6b&amp;#x2F;Phong_components_version_4.png&amp;#x2F;800px-Phong_components_version_4.png&quot;&#x2F;&gt;
&lt;p&gt;following &lt;code&gt;lightPos&lt;&#x2F;code&gt; seen above comes&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;apl&quot; class=&quot;language-apl z-code&quot;&gt;&lt;code class=&quot;language-apl&quot; data-lang=&quot;apl&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;⍝ checkered ball
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;⍵=scene_obj1_ball: l1 phongLight p ro
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;⍝ octahedron
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;⍵=scene_obj2_octa: l2 phongLight p ro
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;⍝ blob
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;⍵=scene_obj3_melted_balls: l3 phongLight p ro
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;⍝ floor
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;⍵=scene_obj4_floor: (l4 phongLight p ro) + (4 checkers ((p[1]) (p[3])))
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;⍵=scene_obj5_frame: (l5 phongLight p ro)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;⍵=scene_obj6_ball: (l6 phongLight p ro) + ( 0.5 × (0.11 checkers ((p[1]) (p[2]))))
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;⍵=scene_obj7_torus: (l6 phongLight p ro) + ( 0.5 × (0.22 checkers ((p[1]) (p[2]))))
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;⍵=scene_obj8_rounded_box: reflective_material ( p rd ro scene_obj8_rounded_box l7)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;assuming of course the &lt;code&gt;scene_objX_NAME&lt;&#x2F;code&gt;-type variables are defined somewhere accessible.
In my case globally like shown below. Note that there is no catchall&#x2F;default expression.
I intentionally chose this so I don’t accidentally forget handling each defined object individually.
But you could of course just write something like:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;apl&quot; class=&quot;language-apl z-code&quot;&gt;&lt;code class=&quot;language-apl&quot; data-lang=&quot;apl&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    ⍵=scene_objX_NAME: (l_X phongLight p ro)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    (l_default phongLight p ro)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With &lt;code&gt;(l_default phongLight p ro)&lt;&#x2F;code&gt; being applied for any unmatched object. &lt;code&gt;phongLight&lt;&#x2F;code&gt;
takes the as its left-side parameter whats defined above by &lt;code&gt;l1&lt;&#x2F;code&gt;-&lt;code&gt;l7&lt;&#x2F;code&gt; and as the parameters on the
right &lt;code&gt;p&lt;&#x2F;code&gt; and &lt;code&gt;ro&lt;&#x2F;code&gt;. &lt;code&gt;ro&lt;&#x2F;code&gt; in this case provides the position of the camera and &lt;code&gt;p&lt;&#x2F;code&gt; being the point on a surface
&lt;code&gt;march&lt;&#x2F;code&gt; detected an intersection with. Based on that information, &lt;code&gt;phongLight&lt;&#x2F;code&gt; returns a color
in the &lt;code&gt;(r g b)&lt;&#x2F;code&gt; &lt;strong&gt;(float float float)&lt;&#x2F;strong&gt; specification. Please note that as &lt;code&gt;⍵=scene_obj8_rounded_box&lt;&#x2F;code&gt; is
a little special special I will document it later on. As its the only object with reflective properties in the scene.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;apl&quot; class=&quot;language-apl z-code&quot;&gt;&lt;code class=&quot;language-apl&quot; data-lang=&quot;apl&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;scene_obj1_ball←1 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;scene_obj2_octa←2
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;scene_obj3_melted_balls←3
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;scene_obj4_floor←4
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;scene_obj5_frame←5
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;scene_obj6_ball←6
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;scene_obj7_torus←7
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;scene_obj8_rounded_box←8
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Knowing the object id in &lt;code&gt;⍵&lt;&#x2F;code&gt; is quite useful here, as it allows us to apply &lt;strong&gt;phong shading&lt;&#x2F;strong&gt; or even textures&#x2F;reflection
properties on various objects individually. If we were to omit it, wed either have to calculate it again by throwing &lt;code&gt;p&lt;&#x2F;code&gt;
back into in the sdf’s again or we would have to assign the same texture and &lt;strong&gt;phong shading&lt;&#x2F;strong&gt; properties to every object.&lt;&#x2F;p&gt;
&lt;p&gt;So now lets look at &lt;code&gt;phongLight&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;The picture below should provide some hints of what is going on in there&lt;&#x2F;p&gt;
&lt;img class=&quot;&quot;src=&quot;https:&amp;#x2F;&amp;#x2F;blog.kakaocdn.net&amp;#x2F;dn&amp;#x2F;ct4wDp&amp;#x2F;btrB5880JNi&amp;#x2F;3goJCO3Sy0tqmiTLemvUC0&amp;#x2F;img.png&quot;&#x2F;&gt;&lt;pre data-lang=&quot;apl&quot; class=&quot;language-apl z-code&quot;&gt;&lt;code class=&quot;language-apl&quot; data-lang=&quot;apl&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;⍝ ⍺ = [ ambient_color(rgb), diffuse_color(rgb), specular_color(rgb), alpha, light_intensity ]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;⍝ ⍵ = [ p ro ]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;phongLight←{
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	p←⊃⍵[1]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	ro←⊃⍵[2]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	⍝ TODO REMOVE 0.5 (DEBUG)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	ambient_color←(⊃⍺[1]) × 0.5
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	diffuse_factor←⊃⍺[2]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	specular_factor←⊃⍺[3]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	alpha←⊃⍺[4]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	light_intensity←⊃⍺[5]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	⍝ estimate the normal vector at point p on the surface
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	n ← estNormal p
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	⍝ light position ( TODO don&amp;#39;t hardcode up here ) 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	light_pos←((0) (3) (1))
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	⍝ vector between the point on the surface and the light position
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	l← norm ( light_pos - p)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	⍝ vector between the point on the surface and the view&#x2F;camera&#x2F;etc vector
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	v← norm ( ro - p)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	⍝ vector  reflecting the light-surface vector on the estimated surfaces normal vector 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	r← norm ( (-l) reflect n )
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	⍝ dot product of both
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	dotln ← l dot n
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	dotrv ← r dot v
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	⍝ the light doesn&amp;#39;t hit the surface at any relevant angle
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	dotln &amp;lt; 0.0: 3 ⍴ 0.0
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	c ← ambient_color + {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;		⍝ angle not in range for specular effect, just apply diffuse color
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;		⍵ &amp;lt; 0.0: diffuse_factor × dotln
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;		⍝ angle in range for specular effect, apply diffuse and specular colors
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;		diffuse_factor × dotln + specular_factor × ( dotrv × alpha )  
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	} dotrv 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	light_intensity × c
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Essentially based on what angle we look at the surface from and the position of a light we
can determine if a &lt;strong&gt;specular&lt;&#x2F;strong&gt; effect should be present or rather just the diffuse lighting effect alone.
Or if the light sources rays never even hit the object in the first place.
Based on if any of the 3 cases &lt;em&gt;(not hit, hit diffuse, hit specular)&lt;&#x2F;em&gt; we apply these effects&lt;&#x2F;p&gt;
&lt;p&gt;Now to &lt;code&gt;scene_obj8_rounded_box:&lt;&#x2F;code&gt; which is special in the sense that it doesn’t just apply &lt;strong&gt;phong shading&lt;&#x2F;strong&gt;
but also simulates a reflective surface.&lt;&#x2F;p&gt;
&lt;p&gt;What essentially happens here is that if &lt;code&gt;obj=scene_obj8_rounded_box: reflective_material&lt;&#x2F;code&gt;, meaning the rounded box “8”
got hit by a ray cast from the camera. Instead of applying &lt;strong&gt;phong shading&lt;&#x2F;strong&gt; like we do with the other objects.
Whats being done here is that similar to how its done when applying &lt;strong&gt;phong shading&lt;&#x2F;strong&gt;. We take into account from what angle were
looking at the object from. Using the estimated normal vector of the point on the surface the camera ray
is pointing at and the view angle we can reflect the ray accordingly.&lt;&#x2F;p&gt;
&lt;img class=&quot;&quot;src=&quot;https:&amp;#x2F;&amp;#x2F;media.geeksforgeeks.org&amp;#x2F;wp-content&amp;#x2F;uploads&amp;#x2F;20220915162140&amp;#x2F;WhatisReflectionofLight.png&quot;&#x2F;&gt;
&lt;p&gt;So knowing what the vector&#x2F;ray direction after being reflected allows us to do the following: We essentially do
the same as what we did when casting rays from the camera upon non reflective objects. But instead of
the ray origin being the camera and the ray direction being determined through which pixel on our plane it goes, the ray
origin is the position our ray originating from the camera hit the reflective surface at. Likewise we use
the reflected directional vector as our new directional vector.&lt;&#x2F;p&gt;
&lt;p&gt;One could think of it roughly as us &lt;del&gt;moving the camera to the point were reflecting from&lt;&#x2F;del&gt; . using
this new information we then undergo the marching loop once again by calling the &lt;code&gt;march&lt;&#x2F;code&gt; function. Note that the maximum
step count was reduced to 20 and the maximum distance to 40 as reflections generally need less accuracy.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;IMPORTANT DETAIL:&lt;&#x2F;strong&gt; note the line specifying &lt;code&gt;ref_surface_p ← ref_surface_p + ref_surface_n × 0.005&lt;&#x2F;code&gt; makes up
a &lt;strong&gt;VERY!!&lt;&#x2F;strong&gt; very important detail. Basically what happens here is that we shift the origin we use when casting the reflected ray by a tiny bit forward &lt;em&gt;(towards the normal vector of the surface)&lt;&#x2F;em&gt; to avoid it intersecting with itself.&lt;&#x2F;p&gt;
&lt;p&gt;Whats left is performing &lt;strong&gt;phong shading&lt;&#x2F;strong&gt; on the object initially hit not the reflection. To then combine that
with the color values returned after performing the reflection. As otherwise wed have a perfect mirror
though (you likely couldn’t tell its a mirror). So in order to be able to tell it apart as a reflective surface
it can’t perfectly reflect everything and needs to perform some sort of modification to the colors it reflects. As for now &lt;code&gt;l7&lt;&#x2F;code&gt; gives it a slightly yellow tint.&lt;&#x2F;p&gt;
&lt;p&gt;The line doing that job is essentially &lt;code&gt;col_obj_self← (light phongLight ref_surface_p  ro )×0.3&lt;&#x2F;code&gt; and at the return segment&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;apl&quot; class=&quot;language-apl z-code&quot;&gt;&lt;code class=&quot;language-apl&quot; data-lang=&quot;apl&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	hit: ((t ref_reflected_final)×0.7) + col_obj_self
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;        	⍝ nothing hit, thus apply background accoring to the reflected vectors orientation
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;        	((sky (ref_reflected_rd[1])  (0 ⌈((ref_reflected_rd[2])+0.12)))×0.5) + col_obj_self
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;apl&quot; class=&quot;language-apl z-code&quot;&gt;&lt;code class=&quot;language-apl&quot; data-lang=&quot;apl&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;reflective_material←{
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	ref_surface_p ← (⊃⍵[1])
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	ref_view_rd ← (⊃⍵[2])
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	ro ← (⊃⍵[3])
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	obj_self← (⊃⍵[4])
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	light ← (⊃⍵[5])
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    	⍝ normal vector of the point we hit the surface at
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	ref_surface_n ← estNormal ref_surface_p
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    	⍝ IMPORTANT !!! V
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    	⍝ slightly offset the origin to cast the reflected ray from in the direction of the reflecting surfaces
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    	⍝ normal vector (which will always point away from it)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	ref_surface_p ← ref_surface_p + ref_surface_n × 0.005
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    	⍝ reflect the camera to reflective surface vector using the surfaces normal vector at that position
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	ref_reflected_rd ← norm (    ref_view_rd reflect ref_surface_n )
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    	⍝ initiate raymarching once more but this time starting from the reflecting surface
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    	⍝ using a slightly reduced  step count&#x2F;max distance
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	ref_reflected_final  ← ( 0 ref_surface_p ref_reflected_rd 70 150) march 0
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	⍝ 1 if the reflected ray hit anything, otherwise 0 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	hit←(ref_reflected_final[1])
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	t←{
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;		dist←⍵[2]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;		obj_is_self← (⍵[3])=obj_self
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;        	⍝ object intersected with itself ( should never happen for now just color it in a vibrant
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;        	⍝ green soits easy to debug or maybe throw an exception 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;		obj_is_self: ( 0 1 0) 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;            		⍝object didn&amp;#39;t intersect with itself, apply phong shading at the point the reflection ray hit at
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;            		phong (dist ref_surface_p ref_reflected_rd (⍵[3]))
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	}
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	col_obj_self← (light phongLight ref_surface_p  ro )×0.3
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    	⍝                      V phong shading at the point the reflection hit at 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	hit: ((t ref_reflected_final)×0.7) + col_obj_self
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;        	⍝ nothing hit, thus apply background accoring to the reflected vectors orientation
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;        	((sky (ref_reflected_rd[1])  (0 ⌈((ref_reflected_rd[2])+0.12)))×0.5) + col_obj_self
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	⍝ TODO ^ instead of using these hardcoded values allow the user to specify the factor of what
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	⍝ rgb components get reflected more and make it bound to distance. For now this is too
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	⍝ enhance obj reflecitons while not reflecting the background too much but thats ofc just a hack
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
        
    </entry>
</feed>
