<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Cubos Engine - Release</title><link href="https://cubos.riscadoa.com/" rel="alternate"/><link href="https://cubos.riscadoa.com/feeds/release.atom.xml" rel="self"/><id>https://cubos.riscadoa.com/</id><updated>2025-06-19T00:00:00+01:00</updated><entry><title>Release 0.7</title><link href="https://cubos.riscadoa.com/blog/release-07/" rel="alternate"/><published>2025-06-19T00:00:00+01:00</published><updated>2025-06-19T00:00:00+01:00</updated><author><name>Cubos Team</name></author><id>tag:cubos.riscadoa.com,2025-06-19:/blog/release-07/</id><summary type="html">&lt;p&gt;A new ImGui theme and inspector, proper support for hierarchies in scenes, distance physics constraints and tons of other improvements.&lt;/p&gt;
</summary><content type="html">&lt;section id="new-0-7-features"&gt;
&lt;h2&gt;New 0.7 Features&lt;/h2&gt;
&lt;p&gt;This blog post covers the most important changes, but you can check out the full changelog in our &lt;a href="https://github.com/GameDevTecnico/cubos/blob/main/CHANGELOG.md"&gt;repository&lt;/a&gt;.&lt;/p&gt;
&lt;section id="on-the-engine"&gt;
&lt;h3&gt;On the Engine&lt;/h3&gt;
&lt;section id="overhauled-imgui-inspector-with-hook-support-riscadoa"&gt;
&lt;h4&gt;Overhauled ImGui Inspector with Hook Support &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/ricardo-antunes/"&gt;&amp;#64;RiscadoA&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;Before 0.7, to inspect a &lt;em&gt;Cubos&lt;/em&gt; value in the ImGui inspector, you used the &lt;code&gt;DataInspector&lt;/code&gt; resource.
This resource provided methods to show and edit types through ImGui, but had no state whatsoever, which was a bit counterintuitive.
Additionally, it was not possible to externally override the behavior of the inspector, which made it impossible to customize the way certain types were displayed or edited.
This meant that, for instance, if the game developer wanted to display a custom UI on the inspector for a component of theirs, it would not be possible.&lt;/p&gt;
&lt;p&gt;This previous implementation was replaced by a new &lt;code&gt;ImGuiInspector&lt;/code&gt; system argument. This can be used in any ImGui system. For example:&lt;/p&gt;
&lt;pre class="m-code"&gt;&lt;span class="n"&gt;cubos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;inspect all velocities&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tagged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;imguiTag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;([](&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Velocity&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;velocities&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ImGuiInspector&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inspector&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;velocity&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;velocities&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;inspector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;edit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;velocity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Velocity of &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ent&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;This new inspector allows overriding its behavior for specific types by using the &lt;code&gt;ImGuiInspector::hook&lt;/code&gt; method.
This paved the way for us to enhance the inspector with new features such as displaying quaternions as Euler angles, breaking down matrices into translation, rotation and scale, and more.
Additionally, support was added for mask and enum types using their respective reflection traits.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="distance-physics-constraint-joaomanita"&gt;
&lt;h4&gt;Distance Physics Constraint &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/joao-manita/"&gt;&amp;#64;joaomanita&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;In version 0.7, we began adding physics constraints that users can set and customize. Previously, only the penetration constraint was available, which was used exclusively for collision solving.
For now, we've added the distance constraint, which ensures either a fixed distance between two physics bodies, or a distance range (similar to a rope).
To add this constraint:&lt;/p&gt;
&lt;pre class="m-code"&gt;&lt;span class="n"&gt;commands&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;relate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ent1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ent2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;DistanceConstraint&lt;/span&gt;&lt;span class="p"&gt;{.&lt;/span&gt;&lt;span class="n"&gt;isRigid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                       &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;minDistance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                       &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;maxDistance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;5.0F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                       &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;localAnchor1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;0.0F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0F&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                                       &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;localAnchor2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;0.0F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0F&lt;/span&gt;&lt;span class="p"&gt;}});&lt;/span&gt;

&lt;span class="n"&gt;commands&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;relate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ent1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ent2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;DistanceConstraint&lt;/span&gt;&lt;span class="p"&gt;{.&lt;/span&gt;&lt;span class="n"&gt;isRigid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                       &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fixedDistance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;5.0F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                       &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;localAnchor1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;0.0F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0F&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;                                       &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;localAnchor2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;0.0F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0F&lt;/span&gt;&lt;span class="p"&gt;}});&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Where isRigid indicates whether it's a fixed distance or a range constraint, and the local anchor values specify the points on each body where the constraint is applied.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="voxel-mesh-frustum-culling-mkuritsu"&gt;
&lt;h4&gt;Voxel Mesh Frustum Culling &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/rodrigo-correia/"&gt;&amp;#64;mkuritsu&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;In this release we used the intersection utilities from the previous release to perform frustum culling on rendered voxel meshes.
Previously, every voxel mesh loaded into the engine would have its data sent to the GPU for rendering, regardless of whether they were visible. This resulted in wasted resources, and that's exactly what this feature addresses.
With frustum culling, only meshes within the camera's visible area are sent to the GPU for drawing, while others are ignored, potentially improving performance in scenes with a large number of objects.&lt;/p&gt;
&lt;p&gt;Frustum culling is performed automatically with any type of camera—whether it's an &lt;a href="https://docs.cubos.riscadoa.com/structcubos_1_1engine_1_1OrthographicCamera.html"&gt;OrthographicCamera&lt;/a&gt; or a &lt;a href="https://docs.cubos.riscadoa.com/structcubos_1_1engine_1_1PerspectiveCamera.html"&gt;PerspectiveCamera&lt;/a&gt;. This means no manual intervention is required to benefit from it.
Additionally, a debug option has been added to the &lt;a href="https://docs.cubos.riscadoa.com/structcubos_1_1engine_1_1Camera.html"&gt;Camera&lt;/a&gt; component, allowing you to freeze (stop) updates to the camera's frustum, keeping it in the last calculated state.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="aabb-and-collider-rework-fallenatlas"&gt;
&lt;h4&gt;AABB and Collider Rework &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/tiago-antunes/"&gt;&amp;#64;fallenatlas&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;In this release, we began reworking the Colliders to make them more streamlined and easier to understand.
Previously, we had the &lt;code&gt;Collider&lt;/code&gt; component, which contained the AABB of the Collision Shape as well as a transform to apply an offset to the AABB.
This component has now been renamed to &lt;code&gt;ColliderAABB&lt;/code&gt; to clarify its purpose, and the transform has been removed, as it only affected the AABB and not the collision shape itself.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;Collider&lt;/code&gt; now represents the owner entity of a collision shape. This distinction is important, as we plan to support collision shapes composed of multiple shapes from child entities of the owner entity. We need an easy way to distinguish them in the hierarchy.
The offset of collision shapes will be determined by the entity's transform when the collision shape is part of a child entity. Otherwise, it is assumed to be centered. This functionality has not been implemented yet, but will begin rolling out in future releases.&lt;/p&gt;
&lt;p&gt;Additionally, we now automatically add the &lt;code&gt;ColliderAABB&lt;/code&gt; when a collision shape is added.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="voxel-shape-inertia-fallenatlas"&gt;
&lt;h4&gt;Voxel Shape Inertia &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/tiago-antunes/"&gt;&amp;#64;fallenatlas&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;Up until now, we had voxel shapes that collided with each other and with boxes. However, the inertia matrix for these shapes was calculated based on the size of the voxel grid, which led to inaccuracies, particularly for shapes with many empty spaces.
Now, we use a custom algorithm that treats each voxel as a point and sums the inertia for each point, relative to the center of mass, to compute the total inertia matrix.
Currently, we only support uniform density, meaning each point has a mass equal to the total mass divided by the number of occupied voxels in the grid.
You can check the implementation of the functions defined &lt;a href="https://docs.cubos.riscadoa.com/inertia_8hpp.html"&gt;here&lt;/a&gt; for more details.&lt;/p&gt;
&lt;p&gt;One important note is that, while we calculate the inertia tensor for this shape, we do not guarantee it will be symmetric, even though it should be by definition.
The matrix is guaranteed to be symmetric only when the shape itself is symmetric. However, in all cases, it’s possible to obtain a symmetric matrix by finding the principal axis of inertia.
This is a minor optimization that makes the inertia more readable, though it's not a priority.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="new-scene-format-riscadoa"&gt;
&lt;h4&gt;New Scene Format &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/ricardo-antunes/"&gt;&amp;#64;RiscadoA&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;With the introduction of relations in the ECS, particularly the &lt;cite&gt;ChildOf&lt;/cite&gt; relation, hierarchies became essential in Cubos scenes.
This posed a problem, as the previous scene format didn’t have an intuitive way to represent hierarchies—scenes were simply flat lists of entities with no parent-child relationships.
To address this, we designed a new scene format where each scene is a JSON file describing an entity, its components and relations, as well as its children, recursively.
It looks like this:&lt;/p&gt;
&lt;pre class="m-code"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;inherit&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ba19170e-65a0-47cd-9bd2-b4ea9447fe22&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;game::Player&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;#camera&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;cubos::engine::PerspectiveCamera&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;fovY&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;#gun&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;inherit&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;6cb09eea-4156-4a75-b0ae-488aac843e05&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;This scene represents an entity that inherits from another scene with the ID &lt;code&gt;ba19170e-65a0-47cd-9bd2-b4ea9447fe22&lt;/code&gt;, meaning we're modifying an existing scene.```
To this base entity, a &lt;code&gt;game::Player&lt;/code&gt; component and two child entities, &lt;code&gt;camera&lt;/code&gt; and &lt;code&gt;gun&lt;/code&gt;, are added.
The &lt;code&gt;camera&lt;/code&gt; entity also receives a &lt;code&gt;cubos::engine::PerspectiveCamera&lt;/code&gt; component, with a field &lt;code&gt;fovY&lt;/code&gt; set to 90, and the &lt;code&gt;gun&lt;/code&gt; entity inherits from another scene, with the ID &lt;code&gt;6cb09eea-4156-4a75-b0ae-488aac843e05&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This format is much more flexible than the previous one, as it allows us to easily expand upon existing scenes by inheriting from them, while also representing hierarchies in a natural way.
The inheritance system has been especially useful in our recent demos, such as for setting different player skins by inheriting from a base player scene and overriding the models used.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="custom-imgui-styling-riscadoa"&gt;
&lt;h4&gt;Custom ImGui Styling &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/ricardo-antunes/"&gt;&amp;#64;RiscadoA&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;In this release we've finally customized the ImGui theme colors and font to match the Cubos brand guidelines.
This change makes the engine's tools UI look more professional and consistent with the overall look of our website and brand.&lt;/p&gt;
&lt;img class="m-image" src="https://cubos.riscadoa.com/images/blog/release/0-7/imgui-sample-theme.png" /&gt;
&lt;/section&gt;
&lt;section id="optional-render-picker-tomas7770"&gt;
&lt;h4&gt;Optional Render Picker &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/tomas-gouveia/"&gt;&amp;#64;tomas7770&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;In the &lt;a href="https://cubos.riscadoa.com/blog/release-06"&gt;previous release's blog post&lt;/a&gt;, we discussed some of the major performance bottlenecks in the graphics renderer. One of them was SSAO, which was made optional to allow disabling it on lower-end devices. The other was the render picker.&lt;/p&gt;
&lt;p&gt;Although work to make the render picker optional had already started, it wasn’t completed due to deadline constraints and some lingering bugs.&lt;/p&gt;
&lt;p&gt;With this release, it's now possible to remove the &lt;a href="https://docs.cubos.riscadoa.com/structcubos_1_1engine_1_1RenderPicker.html"&gt;RenderPicker&lt;/a&gt; component from a render target without breaking the graphics system. While this disables certain features, such as selecting entities with the mouse cursor, in most cases, those features aren't crucial, and the performance cost of render picking is too high to ignore.&lt;/p&gt;
&lt;p&gt;On one particular machine, disabling render picking in our Airships demo running at 1080p on integrated graphics resulted in a jump from 30 FPS to nearly 60 FPS!
This shows how this change makes it much more feasible to run Cubos games on lower-end hardware.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="center-render-voxel-pivot-kuukitenshi"&gt;
&lt;h4&gt;Center Render Voxel Pivot &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/laura-cunha/"&gt;&amp;#64;kuukitenshi&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;Previously, the pivot point for voxel rendering was at the bottom-left corner of each voxel grid. Now, it’s at the center!&lt;/p&gt;
&lt;p&gt;This change makes aligning voxel meshes with other entities much easier, as there's no longer a need to manually adjust offsets.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="on-the-core"&gt;
&lt;h3&gt;On the Core&lt;/h3&gt;
&lt;section id="math-vector-reflection-trait-riscadoa"&gt;
&lt;h4&gt;Math Vector Reflection Trait &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/ricardo-antunes/"&gt;&amp;#64;RiscadoA&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;One issue that had been bothering us for a while was the lack of proper support for math types in the reflection system. This led to the serialization and inspector systems being unaware of them, treating them as simple structs.
To address this, we've added a new reflection trait, &lt;code&gt;VectorTrait&lt;/code&gt;, which identifies types that represent math vectors, such as all the &lt;cite&gt;glm&lt;/cite&gt; vector types.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="entity-destruction-observers-kuukitenshi"&gt;
&lt;h4&gt;Entity Destruction Observers &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/laura-cunha/"&gt;&amp;#64;kuukitenshi&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;Previously, detecting when an entity was being destroyed required manually checking its destruction state. Now, we have an observable for entity destruction that triggers automatically when an entity is destroyed.&lt;/p&gt;
&lt;p&gt;This makes handling such events easier, as we can now simply register a callback that’s invoked upon destruction. It’s especially useful for cleaning up resources or performing actions across systems without needing to repeatedly check if an entity is being destroyed.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="query-match-counting-galaxycrush"&gt;
&lt;h4&gt;Query Match Counting &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/joao-pereira/"&gt;&amp;#64;GalaxyCrush&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;Previously, to count matches in queries, we had to use a for loop to count them after the query was executed.&lt;/p&gt;
&lt;p&gt;Now we added a new &lt;code&gt;count&lt;/code&gt; method to the &lt;a href="https://docs.cubos.riscadoa.com/classcubos_1_1core_1_1ecs_1_1Query.html"&gt;Query&lt;/a&gt; class, which directly returns the number of matches in the query, eliminating the need for a separate loop outside the class.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="wrapper-reflection-trait-srgesus-riscadoa"&gt;
&lt;h4&gt;Wrapper Reflection Trait &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/gabriel-ferreira/"&gt;&amp;#64;SrGesus&lt;/a&gt;, &lt;a href="https://cubos.riscadoa.com/blog/author/ricardo-antunes/"&gt;&amp;#64;RiscadoA&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;A recurring pattern in our codebase are single field wrapper structs, such as &lt;code&gt;Position&lt;/code&gt;, &lt;code&gt;Rotation&lt;/code&gt; and &lt;code&gt;Scale&lt;/code&gt;.
We use these types to give meaning to the data they contain (in this case, math vectors and quaternions), and to distinguish them in the &lt;em&gt;Entity Component System&lt;/em&gt;.
To reflect these types, we previously relied  the &lt;code&gt;FieldsTrait&lt;/code&gt;, as it describes &lt;code&gt;struct&lt;/code&gt; like types.&lt;/p&gt;
&lt;p&gt;When reflection consumers such as the &lt;cite&gt;JSON&lt;/cite&gt; serializer interacted with these types, they would usually treat &lt;code&gt;FieldsTrait&lt;/code&gt; types with a single field as wrappers.
In the case of &lt;cite&gt;JSON&lt;/cite&gt;, this led to shorter more readable output, e.g., instead of:&lt;/p&gt;
&lt;pre class="m-code"&gt;&lt;span class="nt"&gt;&amp;quot;cubos::engine::Position&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;vec&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;x&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;y&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;z&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3.0&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;It would just output:&lt;/p&gt;
&lt;pre class="m-code"&gt;&lt;span class="nt"&gt;&amp;quot;cubos::engine::Position&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;x&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;y&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;z&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3.0&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;However, this behavior became problematic, as not &lt;em&gt;all&lt;/em&gt; struct types with a single field should be treated as wrappers.
For instance, the &lt;code&gt;cubos::engine::PerspectiveCamera&lt;/code&gt; component holds a single field &lt;code&gt;fovY&lt;/code&gt;.
Thus, when serialized to JSON, it would output:&lt;/p&gt;
&lt;pre class="m-code"&gt;&lt;span class="nt"&gt;&amp;quot;cubos::engine::PerspectiveCamera&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;90.0&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;This, of course, is not readable at all. Even worse, if someone were to add a new field to the &lt;code&gt;PerspectiveCamera&lt;/code&gt; component, it would break the serialization format.
image the component now has a new field called &lt;code&gt;farClip&lt;/code&gt;. How would the JSON deserializer know how to deserialize the above JSON?&lt;/p&gt;
&lt;p&gt;To prevent issues like these while still allowing the wrapper behavior for single field structs, we introduced a new reflection trait called &lt;code&gt;WrapperTrait&lt;/code&gt;.
&lt;code&gt;FieldsTrait&lt;/code&gt; types with single fields are now no longer automatically treated as wrappers, and instead, only types with the &lt;code&gt;WrapperTrait&lt;/code&gt; will be serialized in the shorter format.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="on-the-tools"&gt;
&lt;h3&gt;On the Tools&lt;/h3&gt;
&lt;section id="tesseratos-menu-bar-jdbaracho"&gt;
&lt;h4&gt;Tesseratos Menu Bar &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/joao-baracho/"&gt;&amp;#64;jdbaracho&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;Tesseratos now features a menu bar that lets users enable or disable each tool.&lt;/p&gt;
&lt;p&gt;This change brings Tesseratos a step closer to being a fully functional editor, making it easier for more people to build games using &lt;strong&gt;Cubos&lt;/strong&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="auto-scroll-toggle-on-the-console-r-camacho"&gt;
&lt;h4&gt;Auto-scroll Toggle on the Console &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/r-camacho/"&gt;&amp;#64;R-Camacho&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;Previously, we had to scroll manually to view the latest debug messages in the console.&lt;/p&gt;
&lt;p&gt;Now, a new checkbox allows us toggle auto-scroll. When enabled, the console will automatically scroll to display the most recent messages as they appear.&lt;/p&gt;
&lt;img class="m-image" src="https://cubos.riscadoa.com/images/blog/release/0-7/console-auto-scroll.png" /&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="next-steps"&gt;
&lt;h2&gt;Next Steps&lt;/h2&gt;
&lt;p&gt;On the next release we'll be introducing a &lt;em&gt;Lua&lt;/em&gt; scripting plugin, backed by C API bindings to Cubos.
Our goal is to be able to host a game jam focused on our engine by October 2025, and we believe that having a scripting language will be essential for that.&lt;/p&gt;
&lt;p&gt;As usual, one of the focus areas of the team is improving the tooling. The tools team has received a great influx of new contributors, and we're excited to see what they will bring to the table.&lt;/p&gt;
&lt;p&gt;You can check out the full list of things we want to get done in the &lt;a href="https://github.com/GameDevTecnico/cubos/milestone/31"&gt;milestone&lt;/a&gt; for the next release.&lt;/p&gt;
&lt;/section&gt;
</content><category term="Release"/></entry><entry><title>Release 0.6</title><link href="https://cubos.riscadoa.com/blog/release-06/" rel="alternate"/><published>2025-03-12T00:00:00+00:00</published><updated>2025-03-12T00:00:00+00:00</updated><author><name>Cubos Team</name></author><id>tag:cubos.riscadoa.com,2025-03-12:/blog/release-06/</id><summary type="html">&lt;p&gt;A smaller update focused on performance, physics stability and better options for lower end machines.&lt;/p&gt;
</summary><content type="html">&lt;section id="new-0-6-features"&gt;
&lt;h2&gt;New 0.6 Features&lt;/h2&gt;
&lt;p&gt;This blog post covers the most important changes, but you can check out the full changelog in our &lt;a href="https://github.com/GameDevTecnico/cubos/blob/main/CHANGELOG.md"&gt;repository&lt;/a&gt;.&lt;/p&gt;
&lt;section id="on-the-engine"&gt;
&lt;h3&gt;On the Engine&lt;/h3&gt;
&lt;section id="physics-with-warm-starting-fallenatlas"&gt;
&lt;h4&gt;Physics with Warm-Starting &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/tiago-antunes/"&gt;&amp;#64;fallenatlas&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;Continuing the work from the previous release, we finished &lt;strong&gt;warm-starting&lt;/strong&gt; for our physics simulation. Warm-starting uses the information stored in the contact manifold between two bodies, especially the total impulses applied to each contact point in the previous frame, and applies it before solving begins.
It works based on the assumption that the impulses applied in the previous frame are a good estimate for the impulses that will also be applied in the current frame. Therefore, by applying them to the body before solving the collision constraint, the body should already be closer to its ideal position. Over time, these impulses will stabilize (since our solver is a &amp;quot;dirty&amp;quot; solver), resulting in less jitter.
This is particularly effective for stacks of bodies, where the bodies push against each other, creating instability. However, if they're already closer to their ideal position, this instability will be reduced. With warm-starting, we can stack more bodies, and when the stack isn't fully stable, it stays together for longer.&lt;/p&gt;
&lt;p&gt;Here you can see how, in our complex physics sample, the stack holds for much longer than before, although it still falls in the end.&lt;/p&gt;
&lt;img class="m-image" src="https://cubos.riscadoa.com/images/blog/release/0-6/complex_physics_sample_warm_starting.gif" /&gt;
&lt;p&gt;However, if we increase our physics update rate to 60 times per second (rather than our current 30), and the substeps performed in each update to 8 (instead of our current 4), we can see that a stack of 8 blocks holds mostly stable.&lt;/p&gt;
&lt;img class="m-image" src="https://cubos.riscadoa.com/images/blog/release/0-6/complex_physics_sample_1_stack.gif" /&gt;
&lt;p&gt;Unfortunately, our collisions are not optimized to the point where we can have 60 updates per second with many bodies, but the door is open for this upgrade in the future!&lt;/p&gt;
&lt;/section&gt;
&lt;section id="toggleable-ssao-and-resolution-scale-tomas7770"&gt;
&lt;h4&gt;Toggleable SSAO and Resolution Scale &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/tomas-gouveia/"&gt;&amp;#64;tomas7770&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;Some time ago, we profiled &lt;strong&gt;Cubos&lt;/strong&gt;'s graphics engine to determine the main performance bottlenecks. SSAO stood out as the
graphics plugin that took the most frame time. However, due to the way the rendering pipeline was implemented, disabling it to get
better performance wasn't possible without breaking rendering altogether.
Starting with this release, the &lt;a href="https://docs.cubos.riscadoa.com/structcubos_1_1engine_1_1SSAO.html"&gt;SSAO&lt;/a&gt; component can be removed
from a render target to disable this feature.&lt;/p&gt;
&lt;p&gt;In addition, we found that other game engines often default to rendering SSAO textures at half the width/height of the screen resolution,
which greatly improves performance without major loss in quality.
To implement this, we added a &lt;a href="https://docs.cubos.riscadoa.com/structcubos_1_1engine_1_1SSAO.html#ab4c8760eb1582559172373476ff04508"&gt;resolution scale&lt;/a&gt; option to the SSAO component,
which defaults to 0.5, but can be set to any value up to 2.0.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="conditional-shader-compilation-tomas7770"&gt;
&lt;h4&gt;Conditional Shader Compilation &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/tomas-gouveia/"&gt;&amp;#64;tomas7770&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;Another major bottleneck in the graphics renderer is the &lt;a href="https://docs.cubos.riscadoa.com/structcubos_1_1engine_1_1RenderPicker.html"&gt;render picker&lt;/a&gt;, which
allows finding out which entity is visible at a given pixel. As explained in the &lt;strong&gt;Modular Renderer&lt;/strong&gt; section of the &lt;a href="https://cubos.riscadoa.com/coffeen-jam-and-02.html"&gt;0.2 blog post&lt;/a&gt;,
we attempted to mitigate performance loss with Pixel Buffers and double-buffering. But despite this, it remains a demanding feature.&lt;/p&gt;
&lt;p&gt;Just like what happened with SSAO, disabling the render picker wasn't possible. Unlike the former, though, this one required the ability
to change shaders' source code at runtime. To solve this, we added new methods to the &lt;a href="https://docs.cubos.riscadoa.com/classcubos_1_1engine_1_1Shader.html"&gt;Shader&lt;/a&gt;
class to prepend &lt;code&gt;#define&lt;/code&gt; macros and recompile the shader.&lt;/p&gt;
&lt;pre class="m-code"&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vsAsset&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;shaderStage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// unmodified shader&lt;/span&gt;
&lt;span class="n"&gt;vs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vsAsset&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;RENDER_PICKER&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// shader with #define RENDER_PICKER&lt;/span&gt;
&lt;span class="n"&gt;vs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vsAsset&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;MAX_CSM_SPLITS&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;5&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// shader with #define MAX_CSM_SPLITS 5&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Unfortunately, the actual ability to toggle render picking didn't make it to this release, but it should make it to the next one!&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="on-the-core"&gt;
&lt;h3&gt;On the Core&lt;/h3&gt;
&lt;section id="added-frustum-geometry-and-intersection-utilities-mkuritsu"&gt;
&lt;h4&gt;Added Frustum geometry and intersection utilities &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/rodrigo-correia/"&gt;&amp;#64;mkuritsu&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;A new geometry object was added, the &lt;strong&gt;frustum&lt;/strong&gt;, and additionally, two new intersection functions to check if a &lt;a href="https://docs.cubos.riscadoa.com/structcubos_1_1core_1_1geom_1_1Box.html"&gt;box&lt;/a&gt; or a &lt;a href="https://docs.cubos.riscadoa.com/structcubos_1_1core_1_1geom_1_1Capsule.html"&gt;capsule&lt;/a&gt; intersects a frustum.
This new geometry utility will be useful for &lt;em&gt;frustum culling&lt;/em&gt; in a future release, potentially improving graphics performance when rendering large scenes with &lt;strong&gt;Cubos&lt;/strong&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="new-demo-sneak-peek"&gt;
&lt;h2&gt;New Demo Sneak Peek&lt;/h2&gt;
&lt;p&gt;We have been working on a new game made with &lt;strong&gt;Cubos&lt;/strong&gt;, and we're excited to share a sneak peek with you!
It's a competitive multiplayer game where you and your team pilot an airship and fight against other teams.
We plan to implement networked multiplayer, allowing you to play with friends online — this will be a first for &lt;strong&gt;Cubos&lt;/strong&gt;!
Stay tuned for more details after the 0.7 release blog post!&lt;/p&gt;
&lt;img class="m-image" src="https://cubos.riscadoa.com/images/blog/release/0-6/airships_sneak_peek.png" /&gt;
&lt;/section&gt;
&lt;section id="next-steps"&gt;
&lt;h2&gt;Next Steps&lt;/h2&gt;
&lt;p&gt;In the next release, which should be out by the end of April, we're planning to work on the following features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A menu bar and a sensible default layout for &lt;strong&gt;Tesseratos&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;A proper scene editor for &lt;strong&gt;Tesseratos&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Automated inertia computation for arbitrary voxel shapes.&lt;/li&gt;
&lt;li&gt;Frustum culling when rendering.&lt;/li&gt;
&lt;li&gt;Various other performance improvements in the renderer.&lt;/li&gt;
&lt;li&gt;Better integration of mouse input with the high-level input system.&lt;/li&gt;
&lt;li&gt;And many other new features and bug fixes!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the meantime, we'll also be participating in the &lt;a href="https://azulgamejam.com/"&gt;Azul Jam&lt;/a&gt;, a game jam happening over the weekend of March 28nd.
We're excited to see what we can come up with in just 48 hours! A blog post about our experience will be published sometime after the jam.&lt;/p&gt;
&lt;p&gt;You can check out the full list of things we want to get done in the &lt;a href="https://github.com/GameDevTecnico/cubos/milestone/30"&gt;milestone&lt;/a&gt; for the next release.&lt;/p&gt;
&lt;/section&gt;
</content><category term="Release"/><category term="Release"/></entry><entry><title>Release 0.5</title><link href="https://cubos.riscadoa.com/blog/release-05/" rel="alternate"/><published>2025-01-27T00:00:00+00:00</published><updated>2025-01-27T00:00:00+00:00</updated><author><name>Cubos Team</name></author><id>tag:cubos.riscadoa.com,2025-01-27:/blog/release-05/</id><summary type="html">&lt;p&gt;From Voxel collisions, point light shadows and an audio plugin, to web support, text rendering, and FXAA.&lt;/p&gt;
</summary><content type="html">&lt;section id="new-0-5-features"&gt;
&lt;h2&gt;New 0.5 Features&lt;/h2&gt;
&lt;p&gt;This blog post covers the most important changes in the 0.5 release - we've added a lot of new features, such point light shadows, audio support, MSDF text rendering and more!
We've released 0.5 some time ago, but with the exam season and the holidays, we only got around to writing this blog post now.
As usual, you can check out the full changelog in our &lt;a href="https://github.com/GameDevTecnico/cubos/blob/main/CHANGELOG.md"&gt;repository&lt;/a&gt;.&lt;/p&gt;
&lt;section id="on-the-editor"&gt;
&lt;h3&gt;On the Editor&lt;/h3&gt;
&lt;section id="hold-mode-for-debug-camera-jdbaracho"&gt;
&lt;h4&gt;Hold mode for Debug Camera &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/joao-baracho/"&gt;&amp;#64;jdbaracho&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;For debugging purposes, we have a debug camera which allows the user to move around the scene and inspect it.
Previous this camera could only be controlled by locking the camera to the mouse with a toggle.
This was inconvenient when also using the mouse to interact with the editor UI, so we added a new mode where the camera can be rotated by holding a key or mouse button (e.g. the middle mouse button).&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="on-the-engine"&gt;
&lt;h3&gt;On the Engine&lt;/h3&gt;
&lt;section id="point-light-shadows-tomas7770"&gt;
&lt;h4&gt;Point Light Shadows &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/tomas-gouveia/"&gt;&amp;#64;tomas7770&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;Over the past couple of releases, &lt;strong&gt;shadows&lt;/strong&gt; have been gradually introduced to the engine's graphics
renderer, starting with spotlight shadows, and then directional ones. Naturally, the next step was to
implement shadows for point lights, finally completing support for the most common types of lights.&lt;/p&gt;
&lt;p&gt;Point shadows are enabled by adding a &lt;a href="https://docs.cubos.riscadoa.com/structcubos_1_1engine_1_1PointShadowCaster.html"&gt;PointShadowCaster&lt;/a&gt;
component to the light entity.
They behave similarly to spot shadows, lacking all the configurable values of the more complex directional shadows.
You can read the previous blog posts for more detailed information (&lt;a href="https://cubos.riscadoa.com/03-is-here.html"&gt;0.3&lt;/a&gt;, &lt;a href="https://cubos.riscadoa.com/04-is-out.html"&gt;0.4&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;In terms of implementation, point shadows are also very similar to spot shadows, using a shared atlas texture
that stores shadow maps for every point light in a quadtree structure. However, because point lights cast light in
all directions, there are 6 atlas textures, one for each direction of a cube.&lt;/p&gt;
&lt;p&gt;The final result of our shadows engine can be seen in the &lt;a href="https://github.com/GameDevTecnico/cubos/tree/main/engine/samples/render/shadows"&gt;Shadows sample&lt;/a&gt;.
Below is a screenshot of the sample with all light types casting shadows. Some tweaks have been done to better highlight the shadows.&lt;/p&gt;
&lt;img class="m-image" src="https://cubos.riscadoa.com/images/blog/release/0-5/shadows_sample.png" /&gt;
&lt;/section&gt;
&lt;section id="audio-support-through-the-audio-plugin-dageus-diogomsmiranda"&gt;
&lt;h4&gt;Audio Support through the Audio Plugin  &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/joao-nogueira/"&gt;&amp;#64;Dageus&lt;/a&gt;, &lt;a href="https://cubos.riscadoa.com/blog/author/diogo-miranda/"&gt;&amp;#64;diogomsmiranda&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;This release is a significant milestone for the Cubos engine, as it finally introduces Audio functionality!&lt;/p&gt;
&lt;p&gt;The new &lt;code&gt;audioPlugin&lt;/code&gt; leverages the previously implemented &lt;code&gt;Audio Context&lt;/code&gt; to manage audio playback. It introduces two new components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AudioSource&lt;/code&gt;: Attach this component to entities to play audio files in supported formats such as FLAC, MP3 and WAV.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AudioListener&lt;/code&gt;: Attach this component to an entity to capture audio from the scene.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With the plugin, you can now register listeners, and control audio sources with play, pause, and stop functionality. You can also customize audio playback by modifying the &lt;code&gt;AudioSource&lt;/code&gt; properties for each entity, adjusting settings such as volume, pitch, and looping behavior to tailor the sound to your needs.
Due to restrictions in our audio backend, you can only have up to &lt;strong&gt;three active listeners&lt;/strong&gt; at a time. For practical examples of how to use these new audio components (&lt;code&gt;AudioPlay&lt;/code&gt;, &lt;code&gt;AudioPause&lt;/code&gt;, &lt;code&gt;AudioStop&lt;/code&gt;), check out our &lt;a href="https://github.com/GameDevTecnico/cubos/blob/main/engine/samples/audio/main.cpp"&gt;Audio Sample&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="method-to-save-settings-to-files-srgesus"&gt;
&lt;h4&gt;Method to save settings to files &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/gabriel-ferreira/"&gt;&amp;#64;SrGesus&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;Settings&lt;/code&gt; resource was missing some way to interact with its corresponding file,
as it was limited to a startup system that would load the file from a command line
argument with no way for posterior changes to persist which was inconvenient.&lt;/p&gt;
&lt;p&gt;Now there are two new simple methods - &lt;code&gt;save(path, indentation)&lt;/code&gt; and
&lt;code&gt;load(path)&lt;/code&gt; - to save and load the &lt;code&gt;Settings&lt;/code&gt; to and from
&lt;code&gt;cubos::core::data::FileSystem&lt;/code&gt; paths. E.g:&lt;/p&gt;
&lt;pre class="m-code"&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/file.json&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/file_backup.json&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id="collision-detection-between-voxelcollisionshapes-joaomanita"&gt;
&lt;h4&gt;Collision detection between VoxelCollisionShapes &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/joao-manita/"&gt;&amp;#64;joaomanita&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;The engine was only able to able to detect collisons between boxes, now we can add a &lt;a href="https://docs.cubos.riscadoa.com/classcubos_1_1engine_1_1VoxelCollisionShape.html"&gt;VoxelCollisionShape&lt;/a&gt;
to decompose a voxel shape into multiple box collision shapes.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="anti-aliasing-using-the-fxaa-technique-kuukitenshi"&gt;
&lt;h4&gt;Anti-aliasing using the FXAA technique &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/laura-cunha/"&gt;&amp;#64;kuukitenshi&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;We introduced the FXAA (Fast Approximate Anti-Aliasing) technique to reduce jagged edges in the rendered images.
As you can see in the images below, FXAA smooths out the visuals without the performance cost of traditional anti-aliasing methods.&lt;/p&gt;
&lt;img-comparison-slider&gt;
&lt;figure class="before" slot="first"&gt;
&lt;img src="https://cubos.riscadoa.com/images/blog/release/0-5/cars_before.png" style="width: 100%" /&gt;
&lt;figcaption&gt;FXAA Off&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class="after" slot="second"&gt;
&lt;img src="https://cubos.riscadoa.com/images/blog/release/0-5/cars_after.png" style="width: 100%" /&gt;
&lt;figcaption&gt;FXAA On&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/img-comparison-slider&gt;
&lt;/section&gt;
&lt;section id="ui-text-element-using-msdf-for-text-rendering-mkuritsu"&gt;
&lt;h4&gt;UI text element using MSDF for text rendering &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/rodrigo-correia/"&gt;&amp;#64;mkuritsu&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;A significant addition to the Cubos engine was the support for text rendering in the UI, which will greatly improve the capabilities
for communicating with the player in future games developed with the engine.&lt;/p&gt;
&lt;p&gt;This new features comes in the &lt;cite&gt;uiTextPlugin&lt;/cite&gt;, which includes the &lt;cite&gt;UIText&lt;/cite&gt; component, containing all the data needed
to draw text on the screen. The plugin also adds two new asset types:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Font&lt;/strong&gt;: holds the raw font data to be used to create font atlases (.ttf and .otf files supported).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FontAtlas&lt;/strong&gt;: maps characters to their glyph on a given font, with different configurable properties.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In order to draw the text on the screen this plugins uses Multi Signed Distante Fields (MSDFs) with the help from &lt;a href="https://github.com/Chlumsky/msdfgen"&gt;msdfgen&lt;/a&gt;
and &lt;a href="https://github.com/Chlumsky/msdf-atlas-gen"&gt;msdf-atlas-gen&lt;/a&gt;, and &lt;a href="https://freetype.org/"&gt;FreeType&lt;/a&gt; to load different font formats. Below is a screenshot
taken from the UI sample available in the engine showcasing the text rendering in action.&lt;/p&gt;
&lt;img class="m-image" src="https://cubos.riscadoa.com/images/blog/release/0-5/ui-text.png" /&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Currently only the ASCII charset is supported, UTF-8 support will be added in a future release.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="enable-assets-to-be-identified-in-the-code-by-their-file-path-galaxycrush"&gt;
&lt;h4&gt;Enable assets to be identified in the code by their file path &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/joao-pereira/"&gt;&amp;#64;GalaxyCrush&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;Assets could only be identified by their UUID, which can be hard to keep track of for human developers.
Now, they are able to be identified by their path, thus making them easier to handle when developing projects with Cubos.
E.g., you can now do:&lt;/p&gt;
&lt;pre class="m-code"&gt;&lt;span class="n"&gt;Asset&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Scene&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SceneAsset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AnyAsset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/path/to/asset&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;instead of:&lt;/p&gt;
&lt;pre class="m-code"&gt;&lt;span class="n"&gt;Asset&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Scene&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SceneAsset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AnyAsset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;uuid&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id="option-to-use-shadow-normal-offset-bias-algorithm-galaxycrush"&gt;
&lt;h4&gt;Option to use Shadow Normal Offset Bias algorithm &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/joao-pereira/"&gt;&amp;#64;GalaxyCrush&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;We noticed that the shadows had some &lt;a href="https://digitalrune.github.io/DigitalRune-Documentation/html/3f4d959e-9c98-4a97-8d85-7a73c26145d7.htm#Acne"&gt;shadow acne&lt;/a&gt; and/or &lt;a href="https://digitalrune.github.io/DigitalRune-Documentation/html/3f4d959e-9c98-4a97-8d85-7a73c26145d7.htm#PeterPanning"&gt;peter panning&lt;/a&gt; artifacts in some samples. So, to improve it, we implemented the option of using the Shadow Normal Offset Bias algorithm, which improved the quality of the shadows and reduced these artifacts. To use the algorithm, the user simply has to assign a value to the normalOffsetScale field in the light casters &lt;a href="https://docs.cubos.riscadoa.com/structcubos_1_1engine_1_1ShadowCaster.html"&gt;ShadowCaster&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="resource-to-easily-configure-constants-in-the-physics-solver-gcesilva"&gt;
&lt;h4&gt;Resource to easily configure constants in the physics solver &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/goncalo-silva/"&gt;&amp;#64;GCeSilva&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;The physics solver previously included hardcoded constants, which were not easily accessible or modifiable.
A new resource has been added which allows the user to configure these constants, making it easier to tune and debug, even at runtime.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="contact-caching-for-collision-between-box-shapes-fallenatlas"&gt;
&lt;h4&gt;Contact caching for collision between box shapes &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/tiago-antunes/"&gt;&amp;#64;fallenatlas&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;We added contact caching as a first step towards implementing warm-starting. Contact caching consists of keeping information about collisions that were happening in the previous physics update
so that in the next update we can trace them back. This information includes identifiers for each collision manifold and the corrections applied to each contact point. Due to limitations in the current implementation of
collisions between entities, this is currently only supported for box shapes.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="on-the-core"&gt;
&lt;h3&gt;On the Core&lt;/h3&gt;
&lt;section id="a-proper-cmake-configuration-riscadoa"&gt;
&lt;h4&gt;A Proper CMake Configuration &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/ricardo-antunes/"&gt;&amp;#64;RiscadoA&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;While functional, our &lt;a href="https://cmake.org/"&gt;CMake&lt;/a&gt; build configuration was incomplete in terms of features and poorly organized.
As the engine evolved, we recognized the need to install it as a system-wide library for use in other projects.
Before, we always simply added the engine repository as a &lt;code&gt;git&lt;/code&gt; submodule in our projects, which required maintaining a local copy of the entire codebase for each project - an inneficient approach.
To address this, we decided to clean up the CMake configuration, and add installation and &lt;code&gt;find_package&lt;/code&gt; support. As a result, you can now install the whole Cubos project, and to use it in another project, you only need to include the following lines in your &lt;code&gt;CMakeLists.txt&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="m-code"&gt;&lt;span class="nb"&gt;find_package&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;cubos&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;REQUIRED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;target_link_libraries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;your_game&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;PRIVATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;cubos::engine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;One big advantage of this is that we can now also install Quadrados and Tesseratos, the tools we use for making games with Cubos, system-wide, as you would with any other application.
As of now, Cubos has only been packaged for NixOS, but we haven't contributed it to the Nixpkgs repository yet. We plan to do so in the future, and also to package it for other distributions.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="web-support-with-emscripten-riscadoa-luishfonseca"&gt;
&lt;h4&gt;Web Support with Emscripten &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/ricardo-antunes/"&gt;&amp;#64;RiscadoA&lt;/a&gt;, &lt;a href="https://cubos.riscadoa.com/blog/author/luis-fonseca/"&gt;&amp;#64;luishfonseca&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;We've had a pull request open since 0.2 for porting Cubos to the web with &lt;a href="https://emscripten.org/"&gt;Emscripten&lt;/a&gt;, but it was constantly postponed due to some blocking issues being present, and us being focused on other features.
Now, we finally made the final push to get it working, and now Cubos can be compiled to WebAssembly and ran in the browser!&lt;/p&gt;
&lt;p&gt;This is an important feature, as for game jams, for example, it's handy to be able to share your game with others without them having to download anything, and also to be able to play it on any device.
It's a good way to showcase the engine to people who might be interested in using it, but are reluctant to download it.
We plan on embedding each sample on their respective documentation page, but that will be left for a future release.&lt;/p&gt;
&lt;p&gt;One of the major challenges was guaranteeing compatibility with WebGL2. Fortunately, the rendering code is built on top of a rendering API abstraction layer.
We had to make some changes to this layer to guarantee we cover strictly the intersection between the features of OpenGL 3.3 and WebGL2, but we managed to do it without much hassle.
As of now, this means we're making some performance sacrifices, as we're not using advanced features even when they're available. We plan to address this in the future.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="next-steps"&gt;
&lt;h2&gt;Next Steps&lt;/h2&gt;
&lt;p&gt;In the next release, which should be out by February 6th, we're planning to work on the following features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Toggleable gravity on the physics plugin.&lt;/li&gt;
&lt;li&gt;Warm starting in physics solver.&lt;/li&gt;
&lt;li&gt;Graphics performance improvements.&lt;/li&gt;
&lt;li&gt;Transparent voxel rendering.&lt;/li&gt;
&lt;li&gt;Particle system.&lt;/li&gt;
&lt;li&gt;Editor UX improvements, making it very useful.&lt;/li&gt;
&lt;li&gt;New scene editor.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We also developed a demo showcasing the new features of this release, which you will be able to check out pretty soon here.&lt;/p&gt;
&lt;p&gt;You can check out the full list of stuff we want to get done in the &lt;a href="https://github.com/GameDevTecnico/cubos/milestone/29"&gt;milestone&lt;/a&gt; for the next release.&lt;/p&gt;
&lt;/section&gt;
</content><category term="Release"/><category term="Release"/></entry><entry><title>Release 0.4</title><link href="https://cubos.riscadoa.com/blog/release-04/" rel="alternate"/><published>2024-11-05T00:00:00+00:00</published><updated>2024-11-05T00:00:00+00:00</updated><author><name>Cubos Team</name></author><id>tag:cubos.riscadoa.com,2024-11-05:/blog/release-04/</id><summary type="html">&lt;p&gt;Rotating rigid bodies, cascading shadow maps, a standalone editor application, better telemetry and much more!&lt;/p&gt;
</summary><content type="html">&lt;section id="new-0-4-features"&gt;
&lt;h2&gt;New 0.4 Features&lt;/h2&gt;
&lt;p&gt;This blog post covers the most important changes, but you can check out the full changelog in our &lt;a href="https://github.com/GameDevTecnico/cubos/blob/main/CHANGELOG.md"&gt;repository&lt;/a&gt;.&lt;/p&gt;
&lt;section id="on-the-editor"&gt;
&lt;h3&gt;On the Editor&lt;/h3&gt;
&lt;section id="project-management-and-debugging-riscadoa"&gt;
&lt;h4&gt;Project Management and Debugging &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/ricardo-antunes/"&gt;&amp;#64;RiscadoA&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;In this release, we were finally able to make our editor, &lt;strong&gt;Tesseratos&lt;/strong&gt;, a standalone application!
Previously, the editor was a part of the engine itself, which meant if you made changes to the game's code, you had to recompile the editor as well, and restart it.
Now the editor has its own executable, and through it, you can open projects, edit their assets, and even debug them - all without having to restart the editor when recompiling the game.
At this time, the UX is still a bit rough, as we've focused on making it work first.&lt;/p&gt;
&lt;p&gt;One major hurdle we had to overcome was how to make the editor aware of the project's data types, such as its components and resources.
Before, they were part of the same application, and thus, the editor could simply access them directly.
Now, with the editor being a separate application, we needed a way to share this information across different processes.
You can read more about it in the &amp;quot;Type Client and Type Server&amp;quot; section at the end of this post, but in short, with the new reflection functionalities, it is now possible to share type data across different processes, through, for example, a socket.&lt;/p&gt;
&lt;p&gt;In practice, this means that games made with Cubos can now be launched with a debug flag which makes them act as a server at a given port.
Then, the editor is able to connect to this server and extract all of the required debug information.
We also make use of this new connection to allow the editor to send debugging commands to the game, such as pausing, resuming, and stepping the game's execution.&lt;/p&gt;
&lt;p&gt;So, essentially, we've added two new tools to the editor:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A debugger tool, which allows you to connect to a running game and debug it (pause, resume, step, etc.).&lt;/li&gt;
&lt;li&gt;A project manager tool, which allows you to open projects, edit their assets, and launch them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can see them in action in the video below:&lt;/p&gt;
&lt;iframe width="560" height="340" style="display: block; margin: auto" src="https://www.youtube.com/embed/Pu40BjmmW2U" title="" frameBorder="0"   allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"  allowFullScreen&gt;&lt;/iframe&gt;&lt;/section&gt;
&lt;section id="voxel-model-importing-tool-scarface1809"&gt;
&lt;h4&gt;Voxel Model Importing Tool &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/joao-santos/"&gt;&amp;#64;Scarface1809&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;In this release, we've added a highly useful plugin to &lt;strong&gt;Tesseratos&lt;/strong&gt;: a &lt;strong&gt;Voxel Model Importing Tool&lt;/strong&gt;. With this new tool, you can now import &lt;cite&gt;.qb&lt;/cite&gt; files directly within the editor, bypassing the need for the external conversion tool &lt;strong&gt;Quadrados&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Previously, importing voxel models required converting &lt;cite&gt;.qb&lt;/cite&gt; files into &lt;cite&gt;.pal&lt;/cite&gt; and &lt;cite&gt;.grd&lt;/cite&gt; files using &lt;strong&gt;Quadrados&lt;/strong&gt;, a CLI tool, before they could be used in the engine. Now, with the &lt;strong&gt;Voxel Model Importer Plugin&lt;/strong&gt;, the process has been simplified, acting as an interface to handle the conversion process within the editor.&lt;/p&gt;
&lt;p&gt;The tool allows you to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Assign names to the &lt;cite&gt;.pal&lt;/cite&gt; and &lt;cite&gt;.grd&lt;/cite&gt; files.&lt;/li&gt;
&lt;li&gt;Choose the file paths where the &lt;cite&gt;.grd&lt;/cite&gt; files and the &lt;cite&gt;.pal&lt;/cite&gt; file should be saved.&lt;/li&gt;
&lt;li&gt;Specify how many &lt;cite&gt;.grd&lt;/cite&gt; files supported by the &lt;cite&gt;.qb&lt;/cite&gt; file you want to import.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With this tool, importing voxel models into your projects is now faster and easier, allowing for a smoother workflow and less reliance on &lt;strong&gt;Quadrados&lt;/strong&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="on-the-engine"&gt;
&lt;h3&gt;On the Engine&lt;/h3&gt;
&lt;section id="physics-with-rotation-fallenatlas"&gt;
&lt;h4&gt;Physics with Rotation &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/tiago-antunes/"&gt;&amp;#64;fallenatlas&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;We have &lt;strong&gt;rotation&lt;/strong&gt;!&lt;/p&gt;
&lt;img class="m-image" src="https://cubos.riscadoa.com/images/blog/release/0-4/complex_physics_sample_rotations.gif" /&gt;
&lt;p&gt;Since the start of the physics plugin, we always treated rigid bodies as simple particles.
This is because it made the calculations more intuitive, and it reduced the potential amount of mistakes we could make when first starting out. It also made debugging - of penetration solving for example - easier.
With the particle behaviour stabilized, we decided it was time to expand the plugin to consider rotation, and for that we had to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add Collision Manifold and Collision Points computation.&lt;/li&gt;
&lt;li&gt;Add Components for Rotation.&lt;/li&gt;
&lt;li&gt;Expand the Integrator and Solver to compute rotations.&lt;/li&gt;
&lt;/ul&gt;
&lt;section id="collision-manifold-and-collision-points"&gt;
&lt;h5&gt;Collision Manifold and Collision Points&lt;/h5&gt;
&lt;p&gt;Previously, since everything was a particle, we simply computed if there was a collision using SAT, which also returned the normal along which the penetration was the smallest, along with that penetration value.
For rotations we need a &lt;code&gt;ContactManifold&lt;/code&gt; relation, that holds all information about the collision. A &lt;em&gt;Contact Manifold&lt;/em&gt; is effectively a 2D polygon that details the surface of contact between the 2 bodies.
In computer physics the bodies inter-penetrate each other, which does not happen in the real world. The manifold is the aproximation of the real contact surface the bodies would have.
This polygon is described by its vertices, in the form of &lt;em&gt;Contact Points&lt;/em&gt;, all of which contain their position and penetration in &lt;code&gt;ContactPointData&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To compute the manifold we use the Sutherland Hodgman algorithm. Our current implementation was mostly inspired by this &lt;a href="https://research.ncl.ac.uk/game/mastersdegree/gametechnologies/previousinformation/physics5collisionmanifolds/2017%20Tutorial%205%20-%20Collision%20Manifolds.pdf"&gt;tutorial&lt;/a&gt;, which you can check out, to see how it works.&lt;/p&gt;
&lt;pre class="m-code"&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;ContactPointData&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;cubos&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ecs&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Entity&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; Entity to which the normal is relative to.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vec3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;globalOn1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; Position on the entity of the contact in global coordinates.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vec3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;globalOn2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; Position on the other entity of the contact in global coordinates.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vec3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;localOn1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; Position on the entity of the contact in local coordinates.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vec3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;localOn2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; Position on the other entity of the contact in local coordinates.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;penetration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; Penetration of the contact point. Always positive.&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;ContactManifold&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;cubos&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ecs&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Entity&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; Entity to which the normal is relative to.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vec3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;normal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; A contact normal shared by all contacts in this manifold,&lt;/span&gt;
&lt;span class="w"&gt;                                          &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; expressed in the local space of the first entity.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ContactPointData&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; Contact points of this manifold.&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;With this change, our narrow phase firstly checks for collision with SAT, since it's cheaper, and only then computes the manifold.&lt;/p&gt;
&lt;p&gt;The collisions sample was also enhanced so we could visualize this information.&lt;/p&gt;
&lt;img class="m-image" src="https://cubos.riscadoa.com/images/blog/release/0-4/collision_sample_manifold_demo.gif" /&gt;
&lt;/section&gt;
&lt;section id="new-components"&gt;
&lt;h5&gt;New Components&lt;/h5&gt;
&lt;p&gt;The next thing to add were Components to support rotations, such as &lt;code&gt;Inertia&lt;/code&gt;, &lt;code&gt;Torque&lt;/code&gt;, and &lt;code&gt;AngularVelocity&lt;/code&gt;, just to name a few.
To facilitate the creation of entities with box collision shapes, we also added automatic computation of the inertia tensor for the &lt;code&gt;BoxCollisionShape&lt;/code&gt;, which is performed upon adding the &lt;code&gt;Inertia&lt;/code&gt; component and every time &lt;code&gt;Mass&lt;/code&gt; or the dimentions of the shape are changed.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="expand-the-integrator-and-solver"&gt;
&lt;h5&gt;Expand the Integrator and Solver&lt;/h5&gt;
&lt;p&gt;The last step was to add rotation in the Integrator and &lt;code&gt;PenetrationConstraint&lt;/code&gt; Solving.&lt;/p&gt;
&lt;p&gt;The integrator simply takes the &lt;code&gt;AngularImpulse&lt;/code&gt; and &lt;code&gt;Torque&lt;/code&gt; components and handles them similarly to the linear movement components.
We want to note that the &lt;code&gt;Force&lt;/code&gt; component also holds a torque vector, in our current design.
This is because the method we supply to apply a force on a point of the body belongs to &lt;code&gt;Force&lt;/code&gt;, and that method may also apply some torque, if the force isn't aligned with the center of mass.
This hidden torque vector is also used in the Integration phase.&lt;/p&gt;
&lt;pre class="m-code"&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Force&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;addForceOnPoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vec3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;force&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vec3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;localPoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vec3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;centerOfMass&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;mForce&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;force&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;mTorque&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cross&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;localPoint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;centerOfMass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;force&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vec3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mForce&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;0.0F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0F&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vec3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mTorque&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;0.0F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0F&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;PenetrationConstraint&lt;/code&gt; is now solved for each contact point, using their local anchor for relative velocity, separation, and angular velocity calculation at each step.
This involved changing the constraint itself to also have a number of &lt;code&gt;PenetrationConstraintPointData&lt;/code&gt;, which are the same as the manifold points but with extra information to keep track of the constraint solving.
The constraint is now created when the &lt;code&gt;ContactManifold&lt;/code&gt; relation is present between 2 entities, instead of &lt;code&gt;CollidingWith&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="m-code"&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;PenetrationConstraintPointData&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;initialSeparation&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; The separation of the contact point. Negative separation indicates&lt;/span&gt;
&lt;span class="w"&gt;                             &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; penetration.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;normalSpeed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; The relative velocity of the bodies along the normal at the contact point the begging of&lt;/span&gt;
&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; the collision.&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vec3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;localAnchor1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; The local contact point relative to the center of mass of the first body.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vec3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;localAnchor2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; The local contact point relative to the center of mass of the second body.&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;/// Store fixed world-space anchors.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;/// This improves rolling behavior for shapes like balls and capsules. Used for restitution and friction.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vec3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fixedAnchor1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; The world-space contact point relative to the center of mass of the first body.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vec3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fixedAnchor2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; The world-space contact point relative to the center of mass of the second body.&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// separation&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;normalMass&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; Mass to use for normal impulse calculation.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;normalImpulse&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; Accumulated impulse for separation.&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// friction&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;frictionMass1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; Mass to use for friction impulse calculation along the first tangent..&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;frictionMass2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; Mass to use for friction impulse calculation along the second tangent..&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;frictionImpulse1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; Accumulated impulse for friction along the first tangent.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;frictionImpulse2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; Accumulated impulse for friction along the second tangent.&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;PenetrationConstraint&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;cubos&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ecs&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Entity&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; Entity to which the normal is relative to.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vec3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;normal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; Normal of contact on the surface of the entity.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;friction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; Friction of the constraint.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;restitution&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; Restitution coefficient of the constraint.&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;PenetrationConstraintPointData&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;///&amp;lt; Contact points in the contact manifold.&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;And that's it for this very short summary of the physics changes.
Our implementation is still far from perfect. As you might have seen in the sample clip, some movements still don't look very natural, and the boxes should have stayed on top of each other, which is something we'll be working on over the next releases.&lt;/p&gt;
&lt;p&gt;To wrap up, as we promised in the previous release blog post, we've added the &lt;code&gt;PhysicsMaterial&lt;/code&gt; component, which allows users to fine tune the friction and bounciness behaviour of each body. Check it out in our documentation!&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="cascading-shadow-maps-tomas7770"&gt;
&lt;h4&gt;Cascading Shadow Maps &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/tomas-gouveia/"&gt;&amp;#64;tomas7770&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;In the previous release, we introduced &lt;strong&gt;shadows&lt;/strong&gt;.
As shown in the release blog post, this had a significant impact on the quality of Cubos' graphics.
However, due to the complexity and time it took to implement this feature, we were only able to support
spot lights, the type of light for which it's easiest to cast shadows. This obviously restricted the
scenarios where shadows were visible. For this release we aimed to extend shadows support
to directional lights, leaving only point light shadows to be implemented.&lt;/p&gt;
&lt;p&gt;Here are some comparison screenshots showing the difference directional shadows can make.
Try dragging the slider in the middle to compare the before and after!&lt;/p&gt;
&lt;img-comparison-slider&gt;
&lt;figure class="before" slot="first"&gt;
&lt;img src="https://cubos.riscadoa.com/images/blog/release/0-4/scraps_vs_zombies_csm_before.png" style="width: 100%" /&gt;
&lt;figcaption&gt;Before&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class="after" slot="second"&gt;
&lt;img src="https://cubos.riscadoa.com/images/blog/release/0-4/scraps_vs_zombies_csm_after.png" style="width: 100%" /&gt;
&lt;figcaption&gt;After&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/img-comparison-slider&gt;
&lt;img-comparison-slider&gt;
&lt;figure class="before" slot="first"&gt;
&lt;img src="https://cubos.riscadoa.com/images/blog/release/0-4/cars_csm_before.png" style="width: 100%" /&gt;
&lt;figcaption&gt;Before&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class="after" slot="second"&gt;
&lt;img src="https://cubos.riscadoa.com/images/blog/release/0-4/cars_csm_after.png" style="width: 100%" /&gt;
&lt;figcaption&gt;After&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/img-comparison-slider&gt;
&lt;img-comparison-slider&gt;
&lt;figure class="before" slot="first"&gt;
&lt;img src="https://cubos.riscadoa.com/images/blog/release/0-4/surfers_csm_before.png" style="width: 100%" /&gt;
&lt;figcaption&gt;Before&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class="after" slot="second"&gt;
&lt;img src="https://cubos.riscadoa.com/images/blog/release/0-4/surfers_csm_after.png" style="width: 100%" /&gt;
&lt;figcaption&gt;After&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/img-comparison-slider&gt;
&lt;p&gt;As you can see, this adds a whole new level of depth to the engine's graphics.&lt;/p&gt;
&lt;p&gt;Similarly to spot shadows, directional shadows can be enabled by adding a component to the respective light,
in this case a &lt;a href="https://docs.cubos.riscadoa.com/structcubos_1_1engine_1_1DirectionalShadowCaster.html"&gt;DirectionalShadowCaster&lt;/a&gt;.
The &lt;a href="https://github.com/GameDevTecnico/cubos/tree/main/engine/samples/render/shadows"&gt;Shadows sample&lt;/a&gt; has been updated to show this.&lt;/p&gt;
&lt;p&gt;Because directional shadows are more complex than spot shadows, there are more options that can be configured,
namely the maximum and minimum distances for which shadows are casted (directional lights have an unlimited
range, but shadows have a limited range), the distances at which the shadow quality level drops (&amp;quot;splits&amp;quot;), and the resolution
of the shadow map. You may want to tweak the distance values for better results: a lower value will result in
better shadow quality at the expense of range, and vice-versa.&lt;/p&gt;
&lt;p&gt;Due to a technical limitation in our renderer, only one directional light can cast shadows at a given time;
other directional shadow casters will simply be ignored.&lt;/p&gt;
&lt;p&gt;The way directional shadows are implemented is similar to spot shadows. One of the main differences is
that, because of directional lights' unlimited range, a technique known as &lt;a href="https://learnopengl.com/Guest-Articles/2021/CSM"&gt;Cascaded Shadow Mapping&lt;/a&gt;
is employed, rendering the world from a point which varies with the camera's position, and at multiple
distances to balance quality with draw range. This means that instead of just a single shadow map texture
for the light, there is a texture for each camera, multiplied by the number of distances at which the world is rendered.
It's worth noting that each directional shadow caster has its own textures, instead of using a shared shadow atlas like spot casters.
Below are screenshots of the directional shadow map used to draw shadows in &lt;em&gt;Scraps vs Zombies&lt;/em&gt;, as shown earlier.&lt;/p&gt;
&lt;div class="m-row"&gt;
&lt;div class="m-col-m-4"&gt;
&lt;img class="m-image" src="https://cubos.riscadoa.com/images/blog/release/0-4/cascaded_shadow_map_1.png" /&gt;
&lt;/div&gt;
&lt;div class="m-col-m-4"&gt;
&lt;img class="m-image" src="https://cubos.riscadoa.com/images/blog/release/0-4/cascaded_shadow_map_2.png" /&gt;
&lt;/div&gt;
&lt;div class="m-col-m-4"&gt;
&lt;img class="m-image" src="https://cubos.riscadoa.com/images/blog/release/0-4/cascaded_shadow_map_3.png" /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="input-axis-deadzones-kuukitenshi"&gt;
&lt;h4&gt;Input Axis Deadzones &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/laura-cunha/"&gt;&amp;#64;kuukitenshi&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;Previously, dealing with input sources that exhibited drift, like older gamepad joysticks, required developers to manually filter out noise from input data.&lt;/p&gt;
&lt;p&gt;In this release, input deadzones can now be configured directly within the bindings asset, allowing players to adjust it in the settings for their controllers to filter out unwanted noise.&lt;/p&gt;
&lt;p&gt;This enhancement significantly simplifies input handling and ensures a smoother and more reliable gameplay experience, especially for games that heavily rely on precise controller input.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="ortographic-cameras-mkuritsu"&gt;
&lt;h4&gt;Ortographic Cameras &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/rodrigo-correia/"&gt;&amp;#64;mkuritsu&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;Previously we only had support for perspective cameras in Cubos, and additionally, perspective matrix computations were duplicated all over the code.
To address this, we've added a new generic &lt;code&gt;Camera&lt;/code&gt; component that holds the projection matrix of the current camera in use.
Now, the &lt;code&gt;PerspectiveCamera&lt;/code&gt; component is only used to fill in the &lt;code&gt;Camera&lt;/code&gt; component with the correct projection matrix, and code needing the projection matrix can simply query the &lt;code&gt;Camera&lt;/code&gt; component.&lt;/p&gt;
&lt;p&gt;With this, we decoupled the camera type from the rest of code, allowing us to add a new &lt;code&gt;OrtographicCamera&lt;/code&gt; component which uses an ortographic projection instead of a perspective one.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="on-the-core"&gt;
&lt;h3&gt;On the Core&lt;/h3&gt;
&lt;section id="spans-for-profiling-and-tracing-roby2014"&gt;
&lt;h4&gt;Spans for Profiling and Tracing &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/roberto-carlos/"&gt;&amp;#64;roby2014&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;In our ongoing efforts to improve metrics and address performance issues, we are excited to announce the implementation of a new feature for telemetry: Tracing.
This addition will significantly enhance our ability to monitor and understand the execution flow of applications built with &lt;strong&gt;Cubos&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Tracing allows developers to track the execution of their code by creating spans that represent specific periods of execution.
This capability makes it easier to log messages and visualize the flow of an application, providing valuable insights into performance and behaviour.&lt;/p&gt;
&lt;p&gt;In &lt;strong&gt;Cubos&lt;/strong&gt;, tracing is facilitated through a set of macros defined in &lt;code&gt;core/tel/tracing.hpp&lt;/code&gt;:
- &lt;code&gt;CUBOS_SPAN_TRACE&lt;/code&gt;
- &lt;code&gt;CUBOS_SPAN_DEBUG&lt;/code&gt;
- &lt;code&gt;CUBOS_SPAN_INFO&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;From now on, all telemetry components share the same logging level. You can set it by using &lt;code&gt;cubos::core::tel::level&lt;/code&gt; method.
This means that, as an example, trace spans will only be registered if the logger level is set to trace.
We also moved the other components to the &lt;code&gt;tel&lt;/code&gt; namespace (metrics and logging).&lt;/p&gt;
&lt;p&gt;Here's a simple code snippet on how it works and its output:&lt;/p&gt;
&lt;pre class="m-code"&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;cubos&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;tel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Level&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;CUBOS_SPAN_TRACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;this_wont_exist!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// wont exist because trace &amp;lt; debug&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;CUBOS_INFO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;hello from root span!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;CUBOS_SPAN_INFO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;main_span&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// With this macro, a new RAII guard is created. When dropped, exits the span.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// This indicates that we are in the span for the current lexical scope.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Logs and metrics from here will be associated with &amp;#39;main&amp;#39; span.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;CUBOS_INFO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;hello!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;CUBOS_SPAN_DEBUG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;other_scope&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;CUBOS_INFO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;hello again!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;SpanManager&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;manual_span&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cubos&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;tel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Level&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;CUBOS_INFO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entered a manual span&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;SpanManager&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;CUBOS_INFO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;after exit manual span&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="m-code"&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;:03:31.966&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;main.cpp:20&lt;span class="w"&gt; &lt;/span&gt;main&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;thread11740&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;info:&lt;span class="w"&gt; &lt;/span&gt;hello&lt;span class="w"&gt; &lt;/span&gt;from&lt;span class="w"&gt; &lt;/span&gt;root&lt;span class="w"&gt; &lt;/span&gt;span!
&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;:03:31.967&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;main.cpp:26&lt;span class="w"&gt; &lt;/span&gt;main&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;thread11740:main_span&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;info:&lt;span class="w"&gt; &lt;/span&gt;hello!
&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;:03:31.967&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;main.cpp:29&lt;span class="w"&gt; &lt;/span&gt;main&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;thread11740:main_span:other_scope&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;info:&lt;span class="w"&gt; &lt;/span&gt;hello&lt;span class="w"&gt; &lt;/span&gt;again!
&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;:03:31.968&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;main.cpp:34&lt;span class="w"&gt; &lt;/span&gt;main&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;thread11740:main_span:other_scope:manual_span&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;info:&lt;span class="w"&gt; &lt;/span&gt;entered&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;manual&lt;span class="w"&gt; &lt;/span&gt;span
&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;:03:31.969&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;main.cpp:37&lt;span class="w"&gt; &lt;/span&gt;main&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;thread11740:main_span:other_scope&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;info:&lt;span class="w"&gt; &lt;/span&gt;after&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;manual&lt;span class="w"&gt; &lt;/span&gt;span&lt;/pre&gt;
&lt;p&gt;Looking ahead, we aim to develop a &lt;strong&gt;Tesseratos&lt;/strong&gt; plugin that will allow developers to debug and view all possible spans and their execution times
(e.g: &lt;a class="m-link-wrap" href="https://github.com/bwrsandman/imgui-flame-graph"&gt;https://github.com/bwrsandman/imgui-flame-graph&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;This UI will enable developers to interact with the tracing data, providing a comprehensive view of the entire game flow.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="swapping-openal-for-miniaudio-diogomsmiranda-dageus"&gt;
&lt;h4&gt;Swapping OpenAL for Miniaudio &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/diogo-miranda/"&gt;&amp;#64;diogomsmiranda&lt;/a&gt;, &lt;a href="https://cubos.riscadoa.com/blog/author/joao-nogueira/"&gt;&amp;#64;Dageus&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;This release marks the beginning of an exciting new chapter for Cubos: the Audio Plugin.
But before we could start working on the plugin itself, we had to make some changes to the audio backend.
Previously, we were using OpenAL for audio, which no longer aligned with our vision for Cubos, so we decided to switch to &lt;a href="https://miniaud.io"&gt;miniaudio.h&lt;/a&gt;, a lightweight, single-file audio library easy to integrate and use while also sharing the same license as Cubos.
We implemented a new &lt;code&gt;AudioContext&lt;/code&gt; abstraction on the core library, which hides the underlying audio library from the rest of the engine.&lt;/p&gt;
&lt;p&gt;In the next release of &lt;strong&gt;Cubos&lt;/strong&gt;, we're planning to have a fully functional audio plugin, which will allow you to play sounds and music in your games!&lt;/p&gt;
&lt;/section&gt;
&lt;section id="type-client-and-type-server-riscadoa"&gt;
&lt;h4&gt;Type Client and Type Server &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/ricardo-antunes/"&gt;&amp;#64;RiscadoA&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;To separate &lt;strong&gt;Tesseratos&lt;/strong&gt; from the engine into a separate process, we needed a way to share type data across different processes.
This is because the editor needs to know about the project's data types, such as its components and resources, to be able to do work with them, such as showing them in the editor's UI, or editing scene assets.&lt;/p&gt;
&lt;p&gt;To solve this problem, we've added the &lt;code&gt;TypeServer&lt;/code&gt; and &lt;code&gt;TypeClient&lt;/code&gt; classes to the core's reflection module.
The editor contains a &lt;code&gt;TypeClient&lt;/code&gt;, the game contains a &lt;code&gt;TypeServer&lt;/code&gt; and both communicate through an abstract stream, which currently is implemented using a TCP socket.&lt;/p&gt;
&lt;p&gt;Our reflection system is based on the concept of &amp;quot;traits&amp;quot;. A trait is a piece of metadata that describes a type, such as its name, its fields, and its methods.
Both the &lt;code&gt;TypeClient&lt;/code&gt; and the &lt;code&gt;TypeServer&lt;/code&gt; allow registering serialization and deserialization functions for each trait, so that they can be sent across the stream.&lt;/p&gt;
&lt;p&gt;The protocol itself is relatively simple:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The client - the editor - sends a list with the names of the traits it supports.&lt;/li&gt;
&lt;li&gt;The client sends a list with the types it already knows about (for example, primitive types like &lt;code&gt;int&lt;/code&gt; and &lt;code&gt;float&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;The server - the game - sends a list with the types that the client doesn't know about yet. This includes:
- The type name.
- A list of the serialized traits that describe the type.
- The serialized default value for the type, if it has one.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Most of the complexity of this system is on the client side, as it needs to figure out the memory layout of the types it receives from the server.
We do this by basing the memory layout on one of the received traits.
For example, if the server sends a trait that describes an object type with fields, then the client will create a new type which stores these fields in memory.
If the trait describes an array type, then the client will create a new type that stores an array in memory, and so on.&lt;/p&gt;
&lt;p&gt;One major limitation of the current implementation is that it lacks support for traits like &lt;code&gt;NullableTrait&lt;/code&gt;.
This trait contains a function which determines if a value is null or not, and another to make a value null.
How can we pass a function through a stream? We can't. One thing we could do would be to communicate again with the server whenever the client needs to know whether a value is null or not.
For now, we've decided to simply ignore these traits, but we'll eventually need to tackle this issue, as it would allow for better UX in the editor.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="stacktraces-on-crashes-riscadoa"&gt;
&lt;h4&gt;Stacktraces on Crashes &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/ricardo-antunes/"&gt;&amp;#64;RiscadoA&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;Previously, when the engine crashed, it would simply print an error message to the console, and that was it.
We would not get a lot of information about the crash's context, other than the previous log messages.
To debug a crash, we usually spun up a debugger and tried to reproduce it.
This way we could get a stack trace, but it was a bit cumbersome, and when the crash happened in a release build or in a different environment, we were out of luck.&lt;/p&gt;
&lt;p&gt;In order to make our lives easier, we've integrated &lt;a href="https://github.com/jeremy-rifkin/cpptrace"&gt;cpptrace&lt;/a&gt; into the core library.
Now, whenever the engine aborts, it prints a pretty stack trace to &lt;code&gt;stderr&lt;/code&gt;, which includes the function names, the file names, and the line numbers of the functions that were called.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="new-team-organization"&gt;
&lt;h2&gt;New Team Organization&lt;/h2&gt;
&lt;p&gt;We're currently undergoing a major reorganization of the team itself, as it has grown significantly over the past few months.
We have now over 20 developers working on the project, and we're planning to expand even further.&lt;/p&gt;
&lt;p&gt;Previusly, we all met weekly to showcase what each member had been working, and to discuss the project's direction.
Of course, with such a large team, these meetings were becoming increasingly long and unproductive.&lt;/p&gt;
&lt;p&gt;So, we decided to split the big team into smaller teams, each with its own focus. As of now, we have the following teams:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Community&lt;/strong&gt;: responsible for managing the more meta aspects of the project, such as the blog, the Discord server, and the social media.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Graphics&lt;/strong&gt;: responsible for any graphics-related features, such as voxels, UI and gizmos rendering.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Physics&lt;/strong&gt;: responsible for the physics and collisions plugins.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tools&lt;/strong&gt;: responsible for &lt;strong&gt;Tesseratos&lt;/strong&gt;, &lt;strong&gt;Quadrados&lt;/strong&gt; and all other kinds of tooling.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Wildcard&lt;/strong&gt;: catch-all team for any other kind of feature that doesn't fit in the other teams.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now each team meets weekly to discuss their progress and plans, and we have a big meeting less frequently to discuss the project as a whole.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="next-steps"&gt;
&lt;h2&gt;Next Steps&lt;/h2&gt;
&lt;p&gt;In the next release, which should be out by the end of November, we're planning to work on the following features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Scene editing through the new standalone editor, &lt;strong&gt;Tesseratos&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;An Audio plugin, using the new Audio Context abstraction we've added in this release.&lt;/li&gt;
&lt;li&gt;Point light shadows.&lt;/li&gt;
&lt;li&gt;Anti-aliasing.&lt;/li&gt;
&lt;li&gt;MSDF text rendering on our UI plugin.&lt;/li&gt;
&lt;li&gt;Reduce shadow artifacts such as shadow acne and peter panning.&lt;/li&gt;
&lt;li&gt;Toggleable gravity on the physics plugin.&lt;/li&gt;
&lt;li&gt;Voxel collision shapes, where the collision shape is the same as the voxel model.&lt;/li&gt;
&lt;li&gt;Contact point caching to avoid recomputing the collision manifolds every frame.&lt;/li&gt;
&lt;li&gt;Saving settings after changing them in the UI.&lt;/li&gt;
&lt;li&gt;An &lt;code&gt;Active&lt;/code&gt; component to enable and disable all kinds of behaviors in entities.&lt;/li&gt;
&lt;li&gt;Refactoring the whole CMake configuration to support installation and packaging.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Additionally, we're planning to work on a new game project using our engine - now with online multiplayer support!&lt;/p&gt;
&lt;p&gt;You can check out the full list of stuff we want to get done in the &lt;a href="https://github.com/GameDevTecnico/cubos/milestone/28"&gt;milestone&lt;/a&gt; for the next release.&lt;/p&gt;
&lt;/section&gt;
</content><category term="Release"/><category term="Release"/></entry><entry><title>Release 0.3</title><link href="https://cubos.riscadoa.com/blog/release-03/" rel="alternate"/><published>2024-09-09T16:00:00+01:00</published><updated>2024-09-09T16:00:00+01:00</updated><author><name>Cubos Team</name></author><id>tag:cubos.riscadoa.com,2024-09-09:/blog/release-03/</id><summary type="html">&lt;p&gt;Raycasting, shadows, profiling tools, networking utilities, and more!&lt;/p&gt;
</summary><content type="html">&lt;p&gt;This blog post came a bit late due to the summer break, but we're back with a new release!
Features-wise, this release was a tad smaller than the previous one as we spent a lot of time working on non-code related stuff, such as rebranding and marketing the project.&lt;/p&gt;
&lt;section id="new-0-3-features"&gt;
&lt;h2&gt;New 0.3 Features&lt;/h2&gt;
&lt;p&gt;This blog post covers the most important changes, but you can check out the full changelog in our &lt;a href="https://github.com/GameDevTecnico/cubos/blob/main/CHANGELOG.md"&gt;repository&lt;/a&gt;.&lt;/p&gt;
&lt;section id="on-the-editor"&gt;
&lt;h3&gt;On the Editor&lt;/h3&gt;
&lt;section id="groundwork-for-a-standalone-editor-riscadoa"&gt;
&lt;h4&gt;Groundwork for a Standalone Editor &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/ricardo-antunes/"&gt;&amp;#64;RiscadoA&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;The original main goal for this version was to get a first prototype of our standalone editor working.
Sadly, we didn't manage to get it done in time, as it was a bigger task than we anticipated.&lt;/p&gt;
&lt;p&gt;The initial approach, to which we dedicated most of the time, was to have two instances of Cubos running at the same time, on the &lt;strong&gt;same process&lt;/strong&gt; - one for the editor and one for the game.
The game instance would be running within the editor instance, and would be launched by loading the game's code from a shared library (such as a DLL).
With this separation, it would be possible for the editor to interact with the game, pause it, restart it and so on, even across game code changes, without having to restart the editor.&lt;/p&gt;
&lt;p&gt;So, with this in mind, we restructured some parts of the code base to get it flexible enough to support this kind of setup.
Namely, it is now possible to step Cubos instances, reset them, restart them, and other similar operations.
We also added cross platform support for loading Cubos instances from shared libraries, so that we could load the game from the editor.&lt;/p&gt;
&lt;p&gt;This all seems, at first, perfect, but after a team discussion, we realized that this approach of having two Cubos instances in the same process is not ideal at all.
Any game crash would bring down the editor, any memory leak in the game would affect the editor, and infinite loops in the game would freeze the editor.
Since solving the halting problem isn't in our roadmap, we decided that we should discard this approach, and instead try to keep the &lt;strong&gt;editor and the game in two separate processes&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;So, for the next release, we'll be focusing on following this new approach. It will be a big task, and it will be a lot more difficult, as it will require a lot of inter-process communication, but it will be worth it in the end.
It will allows us to have a stable editor, whose performance is not affected (that much at least) by the game, and vice-versa.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="on-the-engine"&gt;
&lt;h3&gt;On the Engine&lt;/h3&gt;
&lt;section id="a-new-physics-solver-fallenatlas"&gt;
&lt;h4&gt;A New Physics Solver &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/tiago-antunes/"&gt;&amp;#64;fallenatlas&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;Upon discovering some potential issues with regards to NVidia's patent of XPBD, some problems with how XPBD handled friction, and stability,
we decided that this would be the ideal moment to switch to another solver.
Recently, Erin Catto shared his &lt;a href="https://box2d.org/posts/2024/02/solver2d/"&gt;comparison of multiple solvers&lt;/a&gt;, and the results of TGS Soft seemed quite promising, so we decided to give it a try... And at this point, our simulation is already more stable than before!&lt;/p&gt;
&lt;p&gt;In simple terms, it differs from XPBD in the sense that it uses impulses instead of changing the position of the bodies directly, however, like XPBD it also uses substeps. On top of this it also uses soft constraints, which is what Soft stands for in it's name.&lt;/p&gt;
&lt;p&gt;Since these changes were mostly in internal systems, from a user stand point, everything works the same way.&lt;/p&gt;
&lt;p&gt;Additionally, we added Friction and Bounciness. For now, these are a predefined value for every body, but will be customizable in the next release with a &lt;code&gt;PhysicsMaterial&lt;/code&gt;.&lt;/p&gt;
&lt;img class="m-image" src="https://cubos.riscadoa.com/images/blog/release/0-3/complex_physics_sample_tgs_soft.gif" /&gt;
&lt;/section&gt;
&lt;section id="raycasting-diogomsmiranda"&gt;
&lt;h4&gt;Raycasting &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/diogo-miranda/"&gt;&amp;#64;diogomsmiranda&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;Raycasting is a commonly used tool in game development which Cubos was lacking until now - it is a technique used to determine the intersection of a ray with an object in a scene.
This allows for a wide range of applications, such as shooting mechanics, object selection, and more.&lt;/p&gt;
&lt;p&gt;This new utility was implemented as a system argument, which means it can be used in any system, by simply adding it as an argument:&lt;/p&gt;
&lt;pre class="m-code"&gt;&lt;span class="n"&gt;cubos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;raycast&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;([](&lt;/span&gt;&lt;span class="n"&gt;Raycast&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;raycast&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// raycast from the origin to -50,0,0&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Raycast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fire&lt;/span&gt;&lt;span class="p"&gt;({{&lt;/span&gt;&lt;span class="mf"&gt;0.0F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;0.0F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;0.0F&lt;/span&gt;&lt;span class="p"&gt;},{&lt;/span&gt;&lt;span class="mf"&gt;-50.0F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;0.0F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;0.0F&lt;/span&gt;&lt;span class="p"&gt;}});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;CUBOS_INFO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Hit entity {} at point {}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;To implement this, we had to handle the two types of colliders that we currently have in Cubos: boxes and capsules.&lt;/p&gt;
&lt;section id="intersection-with-a-box"&gt;
&lt;h5&gt;Intersection with a Box&lt;/h5&gt;
&lt;p&gt;The intersection test with a box is based on the Cyrus-Beck algorithm, which is a line clipping algorithm that is used to find the intersection of a line segment with a convex polygon.&lt;/p&gt;
&lt;p&gt;We can easily define a box by the minimum and maximum values of x,y,z and the ray by its origin and the direction.&lt;/p&gt;
&lt;p&gt;A ray is defined then by the line formula:&lt;/p&gt;
&lt;div class="m-math"&gt;
&lt;svg style="width: 20.195em; height: 1.107em;" viewBox="97.335067 -10.626787 193.872922 10.626798"&gt;
&lt;title&gt;
point = ray.origin + t * ray.direction
&lt;/title&gt;
&lt;defs&gt;
&lt;path id='eq1-g0-3' d='M3.287671-5.104857C3.299626-5.272229 3.299626-5.559153 2.988792-5.559153C2.797509-5.559153 2.642092-5.403736 2.677958-5.248319V-5.092902L2.84533-3.239851L1.315068-4.351681C1.207472-4.411457 1.183562-4.435367 1.099875-4.435367C.932503-4.435367 .777086-4.267995 .777086-4.100623C.777086-3.90934 .896638-3.861519 1.016189-3.801743L2.713823-2.988792L1.06401-2.187796C.872727-2.092154 .777086-2.044334 .777086-1.865006S.932503-1.530262 1.099875-1.530262C1.183562-1.530262 1.207472-1.530262 1.506351-1.75741L2.84533-2.725778L2.666002-.71731C2.666002-.466252 2.881196-.406476 2.976837-.406476C3.120299-.406476 3.299626-.490162 3.299626-.71731L3.120299-2.725778L4.65056-1.613948C4.758157-1.554172 4.782067-1.530262 4.865753-1.530262C5.033126-1.530262 5.188543-1.697634 5.188543-1.865006C5.188543-2.044334 5.080946-2.10411 4.937484-2.175841C4.220174-2.534496 4.196264-2.534496 3.251806-2.976837L4.901619-3.777833C5.092902-3.873474 5.188543-3.921295 5.188543-4.100623S5.033126-4.435367 4.865753-4.435367C4.782067-4.435367 4.758157-4.435367 4.459278-4.208219L3.120299-3.239851L3.287671-5.104857Z'/&gt;
&lt;path id='eq1-g2-43' d='M4.770112-2.761644H8.069738C8.237111-2.761644 8.452304-2.761644 8.452304-2.976837C8.452304-3.203985 8.249066-3.203985 8.069738-3.203985H4.770112V-6.503611C4.770112-6.670984 4.770112-6.886177 4.554919-6.886177C4.327771-6.886177 4.327771-6.682939 4.327771-6.503611V-3.203985H1.028144C.860772-3.203985 .645579-3.203985 .645579-2.988792C.645579-2.761644 .848817-2.761644 1.028144-2.761644H4.327771V.537983C4.327771 .705355 4.327771 .920548 4.542964 .920548C4.770112 .920548 4.770112 .71731 4.770112 .537983V-2.761644Z'/&gt;
&lt;path id='eq1-g2-61' d='M8.069738-3.873474C8.237111-3.873474 8.452304-3.873474 8.452304-4.088667C8.452304-4.315816 8.249066-4.315816 8.069738-4.315816H1.028144C.860772-4.315816 .645579-4.315816 .645579-4.100623C.645579-3.873474 .848817-3.873474 1.028144-3.873474H8.069738ZM8.069738-1.649813C8.237111-1.649813 8.452304-1.649813 8.452304-1.865006C8.452304-2.092154 8.249066-2.092154 8.069738-2.092154H1.028144C.860772-2.092154 .645579-2.092154 .645579-1.876961C.645579-1.649813 .848817-1.649813 1.028144-1.649813H8.069738Z'/&gt;
&lt;path id='eq1-g1-58' d='M2.199751-.573848C2.199751-.920548 1.912827-1.159651 1.625903-1.159651C1.279203-1.159651 1.0401-.872727 1.0401-.585803C1.0401-.239103 1.327024 0 1.613948 0C1.960648 0 2.199751-.286924 2.199751-.573848Z'/&gt;
&lt;path id='eq1-g1-97' d='M3.598506-1.422665C3.53873-1.219427 3.53873-1.195517 3.371357-.968369C3.108344-.633624 2.582316-.119552 2.020423-.119552C1.530262-.119552 1.255293-.561893 1.255293-1.267248C1.255293-1.924782 1.625903-3.263761 1.853051-3.765878C2.259527-4.60274 2.82142-5.033126 3.287671-5.033126C4.076712-5.033126 4.23213-4.052802 4.23213-3.957161C4.23213-3.945205 4.196264-3.789788 4.184309-3.765878L3.598506-1.422665ZM4.363636-4.483188C4.23213-4.794022 3.90934-5.272229 3.287671-5.272229C1.936737-5.272229 .478207-3.526775 .478207-1.75741C.478207-.573848 1.171606 .119552 1.984558 .119552C2.642092 .119552 3.203985-.394521 3.53873-.789041C3.658281-.083686 4.220174 .119552 4.578829 .119552S5.224408-.095641 5.439601-.526027C5.630884-.932503 5.798257-1.661768 5.798257-1.709589C5.798257-1.769365 5.750436-1.817186 5.678705-1.817186C5.571108-1.817186 5.559153-1.75741 5.511333-1.578082C5.332005-.872727 5.104857-.119552 4.614695-.119552C4.267995-.119552 4.244085-.430386 4.244085-.669489C4.244085-.944458 4.27995-1.075965 4.387547-1.542217C4.471233-1.841096 4.531009-2.10411 4.62665-2.450809C5.068991-4.244085 5.176588-4.674471 5.176588-4.746202C5.176588-4.913574 5.045081-5.045081 4.865753-5.045081C4.483188-5.045081 4.387547-4.62665 4.363636-4.483188Z'/&gt;
&lt;path id='eq1-g1-99' d='M4.674471-4.495143C4.447323-4.495143 4.339726-4.495143 4.172354-4.351681C4.100623-4.291905 3.969116-4.112578 3.969116-3.921295C3.969116-3.682192 4.148443-3.53873 4.375592-3.53873C4.662516-3.53873 4.985305-3.777833 4.985305-4.25604C4.985305-4.829888 4.435367-5.272229 3.610461-5.272229C2.044334-5.272229 .478207-3.56264 .478207-1.865006C.478207-.824907 1.123786 .119552 2.343213 .119552C3.969116 .119552 4.99726-1.147696 4.99726-1.303113C4.99726-1.374844 4.925529-1.43462 4.877709-1.43462C4.841843-1.43462 4.829888-1.422665 4.722291-1.315068C3.957161-.298879 2.82142-.119552 2.367123-.119552C1.542217-.119552 1.279203-.836862 1.279203-1.43462C1.279203-1.853051 1.482441-3.012702 1.912827-3.825654C2.223661-4.387547 2.86924-5.033126 3.622416-5.033126C3.777833-5.033126 4.435367-5.009215 4.674471-4.495143Z'/&gt;
&lt;path id='eq1-g1-100' d='M6.01345-7.998007C6.025405-8.045828 6.049315-8.117559 6.049315-8.177335C6.049315-8.296887 5.929763-8.296887 5.905853-8.296887C5.893898-8.296887 5.308095-8.249066 5.248319-8.237111C5.045081-8.225156 4.865753-8.201245 4.65056-8.18929C4.351681-8.16538 4.267995-8.153425 4.267995-7.938232C4.267995-7.81868 4.363636-7.81868 4.531009-7.81868C5.116812-7.81868 5.128767-7.711083 5.128767-7.591532C5.128767-7.519801 5.104857-7.424159 5.092902-7.388294L4.363636-4.483188C4.23213-4.794022 3.90934-5.272229 3.287671-5.272229C1.936737-5.272229 .478207-3.526775 .478207-1.75741C.478207-.573848 1.171606 .119552 1.984558 .119552C2.642092 .119552 3.203985-.394521 3.53873-.789041C3.658281-.083686 4.220174 .119552 4.578829 .119552S5.224408-.095641 5.439601-.526027C5.630884-.932503 5.798257-1.661768 5.798257-1.709589C5.798257-1.769365 5.750436-1.817186 5.678705-1.817186C5.571108-1.817186 5.559153-1.75741 5.511333-1.578082C5.332005-.872727 5.104857-.119552 4.614695-.119552C4.267995-.119552 4.244085-.430386 4.244085-.669489C4.244085-.71731 4.244085-.968369 4.327771-1.303113L6.01345-7.998007ZM3.598506-1.422665C3.53873-1.219427 3.53873-1.195517 3.371357-.968369C3.108344-.633624 2.582316-.119552 2.020423-.119552C1.530262-.119552 1.255293-.561893 1.255293-1.267248C1.255293-1.924782 1.625903-3.263761 1.853051-3.765878C2.259527-4.60274 2.82142-5.033126 3.287671-5.033126C4.076712-5.033126 4.23213-4.052802 4.23213-3.957161C4.23213-3.945205 4.196264-3.789788 4.184309-3.765878L3.598506-1.422665Z'/&gt;
&lt;path id='eq1-g1-101' d='M2.139975-2.773599C2.462765-2.773599 3.275716-2.797509 3.849564-3.012702C4.758157-3.359402 4.841843-4.052802 4.841843-4.267995C4.841843-4.794022 4.387547-5.272229 3.598506-5.272229C2.343213-5.272229 .537983-4.136488 .537983-2.008468C.537983-.753176 1.255293 .119552 2.343213 .119552C3.969116 .119552 4.99726-1.147696 4.99726-1.303113C4.99726-1.374844 4.925529-1.43462 4.877709-1.43462C4.841843-1.43462 4.829888-1.422665 4.722291-1.315068C3.957161-.298879 2.82142-.119552 2.367123-.119552C1.685679-.119552 1.327024-.657534 1.327024-1.542217C1.327024-1.709589 1.327024-2.008468 1.506351-2.773599H2.139975ZM1.566127-3.012702C2.080199-4.853798 3.21594-5.033126 3.598506-5.033126C4.124533-5.033126 4.483188-4.722291 4.483188-4.267995C4.483188-3.012702 2.570361-3.012702 2.068244-3.012702H1.566127Z'/&gt;
&lt;path id='eq1-g1-103' d='M4.040847-1.518306C3.993026-1.327024 3.969116-1.279203 3.813699-1.099875C3.323537-.466252 2.82142-.239103 2.450809-.239103C2.056289-.239103 1.685679-.549938 1.685679-1.374844C1.685679-2.008468 2.044334-3.347447 2.307347-3.88543C2.654047-4.554919 3.19203-5.033126 3.694147-5.033126C4.483188-5.033126 4.638605-4.052802 4.638605-3.981071L4.60274-3.813699L4.040847-1.518306ZM4.782067-4.483188C4.62665-4.829888 4.291905-5.272229 3.694147-5.272229C2.391034-5.272229 .908593-3.634371 .908593-1.853051C.908593-.609714 1.661768 0 2.426899 0C3.060523 0 3.622416-.502117 3.837609-.74122L3.574595 .334745C3.407223 .992279 3.335492 1.291158 2.905106 1.709589C2.414944 2.199751 1.960648 2.199751 1.697634 2.199751C1.338979 2.199751 1.0401 2.175841 .74122 2.080199C1.123786 1.972603 1.219427 1.637858 1.219427 1.506351C1.219427 1.315068 1.075965 1.123786 .812951 1.123786C.526027 1.123786 .215193 1.362889 .215193 1.75741C.215193 2.247572 .705355 2.438854 1.721544 2.438854C3.263761 2.438854 4.064757 1.446575 4.220174 .800996L5.547198-4.554919C5.583064-4.698381 5.583064-4.722291 5.583064-4.746202C5.583064-4.913574 5.451557-5.045081 5.272229-5.045081C4.985305-5.045081 4.817933-4.805978 4.782067-4.483188Z'/&gt;
&lt;path id='eq1-g1-105' d='M3.383313-1.709589C3.383313-1.769365 3.335492-1.817186 3.263761-1.817186C3.156164-1.817186 3.144209-1.78132 3.084433-1.578082C2.773599-.490162 2.283437-.119552 1.888917-.119552C1.745455-.119552 1.578082-.155417 1.578082-.514072C1.578082-.836862 1.721544-1.195517 1.853051-1.554172L2.689913-3.777833C2.725778-3.873474 2.809465-4.088667 2.809465-4.315816C2.809465-4.817933 2.450809-5.272229 1.865006-5.272229C.765131-5.272229 .32279-3.53873 .32279-3.443088C.32279-3.395268 .37061-3.335492 .454296-3.335492C.561893-3.335492 .573848-3.383313 .621669-3.550685C.908593-4.554919 1.362889-5.033126 1.829141-5.033126C1.936737-5.033126 2.139975-5.021171 2.139975-4.638605C2.139975-4.327771 1.984558-3.93325 1.888917-3.670237L1.052055-1.446575C.980324-1.255293 .908593-1.06401 .908593-.848817C.908593-.310834 1.279203 .119552 1.853051 .119552C2.952927 .119552 3.383313-1.625903 3.383313-1.709589ZM3.287671-7.460025C3.287671-7.639352 3.144209-7.854545 2.881196-7.854545C2.606227-7.854545 2.295392-7.591532 2.295392-7.280697C2.295392-6.981818 2.546451-6.886177 2.689913-6.886177C3.012702-6.886177 3.287671-7.197011 3.287671-7.460025Z'/&gt;
&lt;path id='eq1-g1-110' d='M2.462765-3.502864C2.486675-3.574595 2.785554-4.172354 3.227895-4.554919C3.53873-4.841843 3.945205-5.033126 4.411457-5.033126C4.889664-5.033126 5.057036-4.674471 5.057036-4.196264C5.057036-3.514819 4.566874-2.15193 4.327771-1.506351C4.220174-1.219427 4.160399-1.06401 4.160399-.848817C4.160399-.310834 4.531009 .119552 5.104857 .119552C6.216687 .119552 6.635118-1.637858 6.635118-1.709589C6.635118-1.769365 6.587298-1.817186 6.515567-1.817186C6.40797-1.817186 6.396015-1.78132 6.336239-1.578082C6.06127-.597758 5.606974-.119552 5.140722-.119552C5.021171-.119552 4.829888-.131507 4.829888-.514072C4.829888-.812951 4.961395-1.171606 5.033126-1.338979C5.272229-1.996513 5.774346-3.335492 5.774346-4.016936C5.774346-4.734247 5.355915-5.272229 4.447323-5.272229C3.383313-5.272229 2.82142-4.519054 2.606227-4.220174C2.570361-4.901619 2.080199-5.272229 1.554172-5.272229C1.171606-5.272229 .908593-5.045081 .705355-4.638605C.490162-4.208219 .32279-3.490909 .32279-3.443088S.37061-3.335492 .454296-3.335492C.549938-3.335492 .561893-3.347447 .633624-3.622416C.824907-4.351681 1.0401-5.033126 1.518306-5.033126C1.793275-5.033126 1.888917-4.841843 1.888917-4.483188C1.888917-4.220174 1.769365-3.753923 1.685679-3.383313L1.350934-2.092154C1.303113-1.865006 1.171606-1.327024 1.111831-1.111831C1.028144-.800996 .896638-.239103 .896638-.179328C.896638-.011955 1.028144 .119552 1.207472 .119552C1.350934 .119552 1.518306 .047821 1.613948-.131507C1.637858-.191283 1.745455-.609714 1.80523-.848817L2.068244-1.924782L2.462765-3.502864Z'/&gt;
&lt;path id='eq1-g1-111' d='M5.451557-3.287671C5.451557-4.423412 4.710336-5.272229 3.622416-5.272229C2.044334-5.272229 .490162-3.550685 .490162-1.865006C.490162-.729265 1.231382 .119552 2.319303 .119552C3.90934 .119552 5.451557-1.601993 5.451557-3.287671ZM2.331258-.119552C1.733499-.119552 1.291158-.597758 1.291158-1.43462C1.291158-1.984558 1.578082-3.203985 1.912827-3.801743C2.450809-4.722291 3.120299-5.033126 3.610461-5.033126C4.196264-5.033126 4.65056-4.554919 4.65056-3.718057C4.65056-3.239851 4.399502-1.960648 3.945205-1.231382C3.455044-.430386 2.797509-.119552 2.331258-.119552Z'/&gt;
&lt;path id='eq1-g1-112' d='M.514072 1.518306C.430386 1.876961 .382565 1.972603-.107597 1.972603C-.251059 1.972603-.37061 1.972603-.37061 2.199751C-.37061 2.223661-.358655 2.319303-.227148 2.319303C-.071731 2.319303 .095641 2.295392 .251059 2.295392H.765131C1.016189 2.295392 1.625903 2.319303 1.876961 2.319303C1.948692 2.319303 2.092154 2.319303 2.092154 2.10411C2.092154 1.972603 2.008468 1.972603 1.80523 1.972603C1.255293 1.972603 1.219427 1.888917 1.219427 1.793275C1.219427 1.649813 1.75741-.406476 1.829141-.681445C1.960648-.3467 2.283437 .119552 2.905106 .119552C4.25604 .119552 5.71457-1.637858 5.71457-3.395268C5.71457-4.495143 5.092902-5.272229 4.196264-5.272229C3.431133-5.272229 2.785554-4.531009 2.654047-4.363636C2.558406-4.961395 2.092154-5.272229 1.613948-5.272229C1.267248-5.272229 .992279-5.104857 .765131-4.65056C.549938-4.220174 .382565-3.490909 .382565-3.443088S.430386-3.335492 .514072-3.335492C.609714-3.335492 .621669-3.347447 .6934-3.622416C.872727-4.327771 1.099875-5.033126 1.578082-5.033126C1.853051-5.033126 1.948692-4.841843 1.948692-4.483188C1.948692-4.196264 1.912827-4.076712 1.865006-3.861519L.514072 1.518306ZM2.582316-3.730012C2.666002-4.064757 3.000747-4.411457 3.19203-4.578829C3.323537-4.698381 3.718057-5.033126 4.172354-5.033126C4.698381-5.033126 4.937484-4.507098 4.937484-3.88543C4.937484-3.311582 4.60274-1.960648 4.303861-1.338979C4.004981-.6934 3.455044-.119552 2.905106-.119552C2.092154-.119552 1.960648-1.147696 1.960648-1.195517C1.960648-1.231382 1.984558-1.327024 1.996513-1.3868L2.582316-3.730012Z'/&gt;
&lt;path id='eq1-g1-114' d='M4.65056-4.889664C4.27995-4.817933 4.088667-4.554919 4.088667-4.291905C4.088667-4.004981 4.315816-3.90934 4.483188-3.90934C4.817933-3.90934 5.092902-4.196264 5.092902-4.554919C5.092902-4.937484 4.722291-5.272229 4.124533-5.272229C3.646326-5.272229 3.096389-5.057036 2.594271-4.327771C2.510585-4.961395 2.032379-5.272229 1.554172-5.272229C1.08792-5.272229 .848817-4.913574 .705355-4.65056C.502117-4.220174 .32279-3.502864 .32279-3.443088C.32279-3.395268 .37061-3.335492 .454296-3.335492C.549938-3.335492 .561893-3.347447 .633624-3.622416C.812951-4.339726 1.0401-5.033126 1.518306-5.033126C1.80523-5.033126 1.888917-4.829888 1.888917-4.483188C1.888917-4.220174 1.769365-3.753923 1.685679-3.383313L1.350934-2.092154C1.303113-1.865006 1.171606-1.327024 1.111831-1.111831C1.028144-.800996 .896638-.239103 .896638-.179328C.896638-.011955 1.028144 .119552 1.207472 .119552C1.338979 .119552 1.566127 .035866 1.637858-.203238C1.673724-.298879 2.116065-2.10411 2.187796-2.379078C2.247572-2.642092 2.319303-2.893151 2.379078-3.156164C2.426899-3.323537 2.47472-3.514819 2.510585-3.670237C2.546451-3.777833 2.86924-4.363636 3.16812-4.62665C3.311582-4.758157 3.622416-5.033126 4.112578-5.033126C4.303861-5.033126 4.495143-4.99726 4.65056-4.889664Z'/&gt;
&lt;path id='eq1-g1-116' d='M2.402989-4.805978H3.502864C3.730012-4.805978 3.849564-4.805978 3.849564-5.021171C3.849564-5.152677 3.777833-5.152677 3.53873-5.152677H2.486675L2.929016-6.898132C2.976837-7.065504 2.976837-7.089415 2.976837-7.173101C2.976837-7.364384 2.82142-7.47198 2.666002-7.47198C2.570361-7.47198 2.295392-7.436115 2.199751-7.053549L1.733499-5.152677H.609714C.37061-5.152677 .263014-5.152677 .263014-4.925529C.263014-4.805978 .3467-4.805978 .573848-4.805978H1.637858L.848817-1.649813C.753176-1.231382 .71731-1.111831 .71731-.956413C.71731-.394521 1.111831 .119552 1.78132 .119552C2.988792 .119552 3.634371-1.625903 3.634371-1.709589C3.634371-1.78132 3.58655-1.817186 3.514819-1.817186C3.490909-1.817186 3.443088-1.817186 3.419178-1.769365C3.407223-1.75741 3.395268-1.745455 3.311582-1.554172C3.060523-.956413 2.510585-.119552 1.817186-.119552C1.458531-.119552 1.43462-.418431 1.43462-.681445C1.43462-.6934 1.43462-.920548 1.470486-1.06401L2.402989-4.805978Z'/&gt;
&lt;path id='eq1-g1-121' d='M3.144209 1.338979C2.82142 1.793275 2.355168 2.199751 1.769365 2.199751C1.625903 2.199751 1.052055 2.175841 .872727 1.625903C.908593 1.637858 .968369 1.637858 .992279 1.637858C1.350934 1.637858 1.590037 1.327024 1.590037 1.052055S1.362889 .681445 1.183562 .681445C.992279 .681445 .573848 .824907 .573848 1.41071C.573848 2.020423 1.08792 2.438854 1.769365 2.438854C2.964882 2.438854 4.172354 1.338979 4.507098 .011955L5.678705-4.65056C5.69066-4.710336 5.71457-4.782067 5.71457-4.853798C5.71457-5.033126 5.571108-5.152677 5.391781-5.152677C5.284184-5.152677 5.033126-5.104857 4.937484-4.746202L4.052802-1.231382C3.993026-1.016189 3.993026-.992279 3.897385-.860772C3.658281-.526027 3.263761-.119552 2.689913-.119552C2.020423-.119552 1.960648-.777086 1.960648-1.099875C1.960648-1.78132 2.283437-2.701868 2.606227-3.56264C2.737733-3.90934 2.809465-4.076712 2.809465-4.315816C2.809465-4.817933 2.450809-5.272229 1.865006-5.272229C.765131-5.272229 .32279-3.53873 .32279-3.443088C.32279-3.395268 .37061-3.335492 .454296-3.335492C.561893-3.335492 .573848-3.383313 .621669-3.550685C.908593-4.554919 1.362889-5.033126 1.829141-5.033126C1.936737-5.033126 2.139975-5.033126 2.139975-4.638605C2.139975-4.327771 2.008468-3.981071 1.829141-3.526775C1.243337-1.960648 1.243337-1.566127 1.243337-1.279203C1.243337-.143462 2.056289 .119552 2.654047 .119552C3.000747 .119552 3.431133 .011955 3.849564-.430386L3.861519-.418431C3.682192 .286924 3.56264 .753176 3.144209 1.338979Z'/&gt;
&lt;/defs&gt;
&lt;g id='eq1-page1'&gt;
&lt;use x='97.335067' y='-2.324596' xlink:href='#eq1-g1-112'/&gt;
&lt;use x='103.21021' y='-2.324596' xlink:href='#eq1-g1-111'/&gt;
&lt;use x='108.837647' y='-2.324596' xlink:href='#eq1-g1-105'/&gt;
&lt;use x='112.83108' y='-2.324596' xlink:href='#eq1-g1-110'/&gt;
&lt;use x='119.818685' y='-2.324596' xlink:href='#eq1-g1-116'/&gt;
&lt;use x='127.366674' y='-2.324596' xlink:href='#eq1-g2-61'/&gt;
&lt;use x='139.792155' y='-2.324596' xlink:href='#eq1-g1-114'/&gt;
&lt;use x='145.392629' y='-2.324596' xlink:href='#eq1-g1-97'/&gt;
&lt;use x='151.537573' y='-2.324596' xlink:href='#eq1-g1-121'/&gt;
&lt;use x='157.674225' y='-2.324596' xlink:href='#eq1-g1-58'/&gt;
&lt;use x='160.925886' y='-2.324596' xlink:href='#eq1-g1-111'/&gt;
&lt;use x='166.553323' y='-2.324596' xlink:href='#eq1-g1-114'/&gt;
&lt;use x='172.153797' y='-2.324596' xlink:href='#eq1-g1-105'/&gt;
&lt;use x='176.147229' y='-2.324596' xlink:href='#eq1-g1-103'/&gt;
&lt;use x='182.181485' y='-2.324596' xlink:href='#eq1-g1-105'/&gt;
&lt;use x='186.174918' y='-2.324596' xlink:href='#eq1-g1-110'/&gt;
&lt;use x='195.819187' y='-2.324596' xlink:href='#eq1-g2-43'/&gt;
&lt;use x='207.580502' y='-2.324596' xlink:href='#eq1-g1-116'/&gt;
&lt;use x='214.464325' y='-2.324596' xlink:href='#eq1-g0-3'/&gt;
&lt;use x='223.098595' y='-2.324596' xlink:href='#eq1-g1-114'/&gt;
&lt;use x='228.699069' y='-2.324596' xlink:href='#eq1-g1-97'/&gt;
&lt;use x='234.844013' y='-2.324596' xlink:href='#eq1-g1-121'/&gt;
&lt;use x='240.980665' y='-2.324596' xlink:href='#eq1-g1-58'/&gt;
&lt;use x='244.232326' y='-2.324596' xlink:href='#eq1-g1-100'/&gt;
&lt;use x='250.315019' y='-2.324596' xlink:href='#eq1-g1-105'/&gt;
&lt;use x='254.308451' y='-2.324596' xlink:href='#eq1-g1-114'/&gt;
&lt;use x='259.908925' y='-2.324596' xlink:href='#eq1-g1-101'/&gt;
&lt;use x='265.334365' y='-2.324596' xlink:href='#eq1-g1-99'/&gt;
&lt;use x='270.372353' y='-2.324596' xlink:href='#eq1-g1-116'/&gt;
&lt;use x='274.599513' y='-2.324596' xlink:href='#eq1-g1-105'/&gt;
&lt;use x='278.592945' y='-2.324596' xlink:href='#eq1-g1-111'/&gt;
&lt;use x='284.220383' y='-2.324596' xlink:href='#eq1-g1-110'/&gt;
&lt;/g&gt;
&lt;/svg&gt;&lt;/div&gt;
&lt;p&gt;Being t a scalar value that represents the distance from the ray's origin to the point.&lt;/p&gt;
&lt;p&gt;Our objective is to find t, and check if the point is in the &amp;quot;right&amp;quot; side of the ray (the side that the ray is pointing to).&lt;/p&gt;
&lt;p&gt;For that we can rearrange the previous formula to:&lt;/p&gt;
&lt;div class="m-math"&gt;
&lt;svg style="width: 20.597em; height: 1.245em;" viewBox="95.40479 -11.955168 197.733475 11.955168"&gt;
&lt;title&gt;
t = (point - ray.origin) / ray.direction
&lt;/title&gt;
&lt;defs&gt;
&lt;path id='eq2-g0-0' d='M7.878456-2.749689C8.081694-2.749689 8.296887-2.749689 8.296887-2.988792S8.081694-3.227895 7.878456-3.227895H1.41071C1.207472-3.227895 .992279-3.227895 .992279-2.988792S1.207472-2.749689 1.41071-2.749689H7.878456Z'/&gt;
&lt;path id='eq2-g2-40' d='M3.88543 2.905106C3.88543 2.86924 3.88543 2.84533 3.682192 2.642092C2.486675 1.43462 1.817186-.537983 1.817186-2.976837C1.817186-5.296139 2.379078-7.292653 3.765878-8.703362C3.88543-8.810959 3.88543-8.834869 3.88543-8.870735C3.88543-8.942466 3.825654-8.966376 3.777833-8.966376C3.622416-8.966376 2.642092-8.105604 2.056289-6.933998C1.446575-5.726526 1.171606-4.447323 1.171606-2.976837C1.171606-1.912827 1.338979-.490162 1.960648 .789041C2.666002 2.223661 3.646326 3.000747 3.777833 3.000747C3.825654 3.000747 3.88543 2.976837 3.88543 2.905106Z'/&gt;
&lt;path id='eq2-g2-41' d='M3.371357-2.976837C3.371357-3.88543 3.251806-5.36787 2.582316-6.75467C1.876961-8.18929 .896638-8.966376 .765131-8.966376C.71731-8.966376 .657534-8.942466 .657534-8.870735C.657534-8.834869 .657534-8.810959 .860772-8.607721C2.056289-7.400249 2.725778-5.427646 2.725778-2.988792C2.725778-.669489 2.163885 1.327024 .777086 2.737733C.657534 2.84533 .657534 2.86924 .657534 2.905106C.657534 2.976837 .71731 3.000747 .765131 3.000747C.920548 3.000747 1.900872 2.139975 2.486675 .968369C3.096389-.251059 3.371357-1.542217 3.371357-2.976837Z'/&gt;
&lt;path id='eq2-g2-61' d='M8.069738-3.873474C8.237111-3.873474 8.452304-3.873474 8.452304-4.088667C8.452304-4.315816 8.249066-4.315816 8.069738-4.315816H1.028144C.860772-4.315816 .645579-4.315816 .645579-4.100623C.645579-3.873474 .848817-3.873474 1.028144-3.873474H8.069738ZM8.069738-1.649813C8.237111-1.649813 8.452304-1.649813 8.452304-1.865006C8.452304-2.092154 8.249066-2.092154 8.069738-2.092154H1.028144C.860772-2.092154 .645579-2.092154 .645579-1.876961C.645579-1.649813 .848817-1.649813 1.028144-1.649813H8.069738Z'/&gt;
&lt;path id='eq2-g1-58' d='M2.199751-.573848C2.199751-.920548 1.912827-1.159651 1.625903-1.159651C1.279203-1.159651 1.0401-.872727 1.0401-.585803C1.0401-.239103 1.327024 0 1.613948 0C1.960648 0 2.199751-.286924 2.199751-.573848Z'/&gt;
&lt;path id='eq2-g1-61' d='M5.128767-8.524035C5.128767-8.53599 5.200498-8.715318 5.200498-8.739228C5.200498-8.88269 5.080946-8.966376 4.985305-8.966376C4.925529-8.966376 4.817933-8.966376 4.722291-8.703362L.71731 2.546451C.71731 2.558406 .645579 2.737733 .645579 2.761644C.645579 2.905106 .765131 2.988792 .860772 2.988792C.932503 2.988792 1.0401 2.976837 1.123786 2.725778L5.128767-8.524035Z'/&gt;
&lt;path id='eq2-g1-97' d='M3.598506-1.422665C3.53873-1.219427 3.53873-1.195517 3.371357-.968369C3.108344-.633624 2.582316-.119552 2.020423-.119552C1.530262-.119552 1.255293-.561893 1.255293-1.267248C1.255293-1.924782 1.625903-3.263761 1.853051-3.765878C2.259527-4.60274 2.82142-5.033126 3.287671-5.033126C4.076712-5.033126 4.23213-4.052802 4.23213-3.957161C4.23213-3.945205 4.196264-3.789788 4.184309-3.765878L3.598506-1.422665ZM4.363636-4.483188C4.23213-4.794022 3.90934-5.272229 3.287671-5.272229C1.936737-5.272229 .478207-3.526775 .478207-1.75741C.478207-.573848 1.171606 .119552 1.984558 .119552C2.642092 .119552 3.203985-.394521 3.53873-.789041C3.658281-.083686 4.220174 .119552 4.578829 .119552S5.224408-.095641 5.439601-.526027C5.630884-.932503 5.798257-1.661768 5.798257-1.709589C5.798257-1.769365 5.750436-1.817186 5.678705-1.817186C5.571108-1.817186 5.559153-1.75741 5.511333-1.578082C5.332005-.872727 5.104857-.119552 4.614695-.119552C4.267995-.119552 4.244085-.430386 4.244085-.669489C4.244085-.944458 4.27995-1.075965 4.387547-1.542217C4.471233-1.841096 4.531009-2.10411 4.62665-2.450809C5.068991-4.244085 5.176588-4.674471 5.176588-4.746202C5.176588-4.913574 5.045081-5.045081 4.865753-5.045081C4.483188-5.045081 4.387547-4.62665 4.363636-4.483188Z'/&gt;
&lt;path id='eq2-g1-99' d='M4.674471-4.495143C4.447323-4.495143 4.339726-4.495143 4.172354-4.351681C4.100623-4.291905 3.969116-4.112578 3.969116-3.921295C3.969116-3.682192 4.148443-3.53873 4.375592-3.53873C4.662516-3.53873 4.985305-3.777833 4.985305-4.25604C4.985305-4.829888 4.435367-5.272229 3.610461-5.272229C2.044334-5.272229 .478207-3.56264 .478207-1.865006C.478207-.824907 1.123786 .119552 2.343213 .119552C3.969116 .119552 4.99726-1.147696 4.99726-1.303113C4.99726-1.374844 4.925529-1.43462 4.877709-1.43462C4.841843-1.43462 4.829888-1.422665 4.722291-1.315068C3.957161-.298879 2.82142-.119552 2.367123-.119552C1.542217-.119552 1.279203-.836862 1.279203-1.43462C1.279203-1.853051 1.482441-3.012702 1.912827-3.825654C2.223661-4.387547 2.86924-5.033126 3.622416-5.033126C3.777833-5.033126 4.435367-5.009215 4.674471-4.495143Z'/&gt;
&lt;path id='eq2-g1-100' d='M6.01345-7.998007C6.025405-8.045828 6.049315-8.117559 6.049315-8.177335C6.049315-8.296887 5.929763-8.296887 5.905853-8.296887C5.893898-8.296887 5.308095-8.249066 5.248319-8.237111C5.045081-8.225156 4.865753-8.201245 4.65056-8.18929C4.351681-8.16538 4.267995-8.153425 4.267995-7.938232C4.267995-7.81868 4.363636-7.81868 4.531009-7.81868C5.116812-7.81868 5.128767-7.711083 5.128767-7.591532C5.128767-7.519801 5.104857-7.424159 5.092902-7.388294L4.363636-4.483188C4.23213-4.794022 3.90934-5.272229 3.287671-5.272229C1.936737-5.272229 .478207-3.526775 .478207-1.75741C.478207-.573848 1.171606 .119552 1.984558 .119552C2.642092 .119552 3.203985-.394521 3.53873-.789041C3.658281-.083686 4.220174 .119552 4.578829 .119552S5.224408-.095641 5.439601-.526027C5.630884-.932503 5.798257-1.661768 5.798257-1.709589C5.798257-1.769365 5.750436-1.817186 5.678705-1.817186C5.571108-1.817186 5.559153-1.75741 5.511333-1.578082C5.332005-.872727 5.104857-.119552 4.614695-.119552C4.267995-.119552 4.244085-.430386 4.244085-.669489C4.244085-.71731 4.244085-.968369 4.327771-1.303113L6.01345-7.998007ZM3.598506-1.422665C3.53873-1.219427 3.53873-1.195517 3.371357-.968369C3.108344-.633624 2.582316-.119552 2.020423-.119552C1.530262-.119552 1.255293-.561893 1.255293-1.267248C1.255293-1.924782 1.625903-3.263761 1.853051-3.765878C2.259527-4.60274 2.82142-5.033126 3.287671-5.033126C4.076712-5.033126 4.23213-4.052802 4.23213-3.957161C4.23213-3.945205 4.196264-3.789788 4.184309-3.765878L3.598506-1.422665Z'/&gt;
&lt;path id='eq2-g1-101' d='M2.139975-2.773599C2.462765-2.773599 3.275716-2.797509 3.849564-3.012702C4.758157-3.359402 4.841843-4.052802 4.841843-4.267995C4.841843-4.794022 4.387547-5.272229 3.598506-5.272229C2.343213-5.272229 .537983-4.136488 .537983-2.008468C.537983-.753176 1.255293 .119552 2.343213 .119552C3.969116 .119552 4.99726-1.147696 4.99726-1.303113C4.99726-1.374844 4.925529-1.43462 4.877709-1.43462C4.841843-1.43462 4.829888-1.422665 4.722291-1.315068C3.957161-.298879 2.82142-.119552 2.367123-.119552C1.685679-.119552 1.327024-.657534 1.327024-1.542217C1.327024-1.709589 1.327024-2.008468 1.506351-2.773599H2.139975ZM1.566127-3.012702C2.080199-4.853798 3.21594-5.033126 3.598506-5.033126C4.124533-5.033126 4.483188-4.722291 4.483188-4.267995C4.483188-3.012702 2.570361-3.012702 2.068244-3.012702H1.566127Z'/&gt;
&lt;path id='eq2-g1-103' d='M4.040847-1.518306C3.993026-1.327024 3.969116-1.279203 3.813699-1.099875C3.323537-.466252 2.82142-.239103 2.450809-.239103C2.056289-.239103 1.685679-.549938 1.685679-1.374844C1.685679-2.008468 2.044334-3.347447 2.307347-3.88543C2.654047-4.554919 3.19203-5.033126 3.694147-5.033126C4.483188-5.033126 4.638605-4.052802 4.638605-3.981071L4.60274-3.813699L4.040847-1.518306ZM4.782067-4.483188C4.62665-4.829888 4.291905-5.272229 3.694147-5.272229C2.391034-5.272229 .908593-3.634371 .908593-1.853051C.908593-.609714 1.661768 0 2.426899 0C3.060523 0 3.622416-.502117 3.837609-.74122L3.574595 .334745C3.407223 .992279 3.335492 1.291158 2.905106 1.709589C2.414944 2.199751 1.960648 2.199751 1.697634 2.199751C1.338979 2.199751 1.0401 2.175841 .74122 2.080199C1.123786 1.972603 1.219427 1.637858 1.219427 1.506351C1.219427 1.315068 1.075965 1.123786 .812951 1.123786C.526027 1.123786 .215193 1.362889 .215193 1.75741C.215193 2.247572 .705355 2.438854 1.721544 2.438854C3.263761 2.438854 4.064757 1.446575 4.220174 .800996L5.547198-4.554919C5.583064-4.698381 5.583064-4.722291 5.583064-4.746202C5.583064-4.913574 5.451557-5.045081 5.272229-5.045081C4.985305-5.045081 4.817933-4.805978 4.782067-4.483188Z'/&gt;
&lt;path id='eq2-g1-105' d='M3.383313-1.709589C3.383313-1.769365 3.335492-1.817186 3.263761-1.817186C3.156164-1.817186 3.144209-1.78132 3.084433-1.578082C2.773599-.490162 2.283437-.119552 1.888917-.119552C1.745455-.119552 1.578082-.155417 1.578082-.514072C1.578082-.836862 1.721544-1.195517 1.853051-1.554172L2.689913-3.777833C2.725778-3.873474 2.809465-4.088667 2.809465-4.315816C2.809465-4.817933 2.450809-5.272229 1.865006-5.272229C.765131-5.272229 .32279-3.53873 .32279-3.443088C.32279-3.395268 .37061-3.335492 .454296-3.335492C.561893-3.335492 .573848-3.383313 .621669-3.550685C.908593-4.554919 1.362889-5.033126 1.829141-5.033126C1.936737-5.033126 2.139975-5.021171 2.139975-4.638605C2.139975-4.327771 1.984558-3.93325 1.888917-3.670237L1.052055-1.446575C.980324-1.255293 .908593-1.06401 .908593-.848817C.908593-.310834 1.279203 .119552 1.853051 .119552C2.952927 .119552 3.383313-1.625903 3.383313-1.709589ZM3.287671-7.460025C3.287671-7.639352 3.144209-7.854545 2.881196-7.854545C2.606227-7.854545 2.295392-7.591532 2.295392-7.280697C2.295392-6.981818 2.546451-6.886177 2.689913-6.886177C3.012702-6.886177 3.287671-7.197011 3.287671-7.460025Z'/&gt;
&lt;path id='eq2-g1-110' d='M2.462765-3.502864C2.486675-3.574595 2.785554-4.172354 3.227895-4.554919C3.53873-4.841843 3.945205-5.033126 4.411457-5.033126C4.889664-5.033126 5.057036-4.674471 5.057036-4.196264C5.057036-3.514819 4.566874-2.15193 4.327771-1.506351C4.220174-1.219427 4.160399-1.06401 4.160399-.848817C4.160399-.310834 4.531009 .119552 5.104857 .119552C6.216687 .119552 6.635118-1.637858 6.635118-1.709589C6.635118-1.769365 6.587298-1.817186 6.515567-1.817186C6.40797-1.817186 6.396015-1.78132 6.336239-1.578082C6.06127-.597758 5.606974-.119552 5.140722-.119552C5.021171-.119552 4.829888-.131507 4.829888-.514072C4.829888-.812951 4.961395-1.171606 5.033126-1.338979C5.272229-1.996513 5.774346-3.335492 5.774346-4.016936C5.774346-4.734247 5.355915-5.272229 4.447323-5.272229C3.383313-5.272229 2.82142-4.519054 2.606227-4.220174C2.570361-4.901619 2.080199-5.272229 1.554172-5.272229C1.171606-5.272229 .908593-5.045081 .705355-4.638605C.490162-4.208219 .32279-3.490909 .32279-3.443088S.37061-3.335492 .454296-3.335492C.549938-3.335492 .561893-3.347447 .633624-3.622416C.824907-4.351681 1.0401-5.033126 1.518306-5.033126C1.793275-5.033126 1.888917-4.841843 1.888917-4.483188C1.888917-4.220174 1.769365-3.753923 1.685679-3.383313L1.350934-2.092154C1.303113-1.865006 1.171606-1.327024 1.111831-1.111831C1.028144-.800996 .896638-.239103 .896638-.179328C.896638-.011955 1.028144 .119552 1.207472 .119552C1.350934 .119552 1.518306 .047821 1.613948-.131507C1.637858-.191283 1.745455-.609714 1.80523-.848817L2.068244-1.924782L2.462765-3.502864Z'/&gt;
&lt;path id='eq2-g1-111' d='M5.451557-3.287671C5.451557-4.423412 4.710336-5.272229 3.622416-5.272229C2.044334-5.272229 .490162-3.550685 .490162-1.865006C.490162-.729265 1.231382 .119552 2.319303 .119552C3.90934 .119552 5.451557-1.601993 5.451557-3.287671ZM2.331258-.119552C1.733499-.119552 1.291158-.597758 1.291158-1.43462C1.291158-1.984558 1.578082-3.203985 1.912827-3.801743C2.450809-4.722291 3.120299-5.033126 3.610461-5.033126C4.196264-5.033126 4.65056-4.554919 4.65056-3.718057C4.65056-3.239851 4.399502-1.960648 3.945205-1.231382C3.455044-.430386 2.797509-.119552 2.331258-.119552Z'/&gt;
&lt;path id='eq2-g1-112' d='M.514072 1.518306C.430386 1.876961 .382565 1.972603-.107597 1.972603C-.251059 1.972603-.37061 1.972603-.37061 2.199751C-.37061 2.223661-.358655 2.319303-.227148 2.319303C-.071731 2.319303 .095641 2.295392 .251059 2.295392H.765131C1.016189 2.295392 1.625903 2.319303 1.876961 2.319303C1.948692 2.319303 2.092154 2.319303 2.092154 2.10411C2.092154 1.972603 2.008468 1.972603 1.80523 1.972603C1.255293 1.972603 1.219427 1.888917 1.219427 1.793275C1.219427 1.649813 1.75741-.406476 1.829141-.681445C1.960648-.3467 2.283437 .119552 2.905106 .119552C4.25604 .119552 5.71457-1.637858 5.71457-3.395268C5.71457-4.495143 5.092902-5.272229 4.196264-5.272229C3.431133-5.272229 2.785554-4.531009 2.654047-4.363636C2.558406-4.961395 2.092154-5.272229 1.613948-5.272229C1.267248-5.272229 .992279-5.104857 .765131-4.65056C.549938-4.220174 .382565-3.490909 .382565-3.443088S.430386-3.335492 .514072-3.335492C.609714-3.335492 .621669-3.347447 .6934-3.622416C.872727-4.327771 1.099875-5.033126 1.578082-5.033126C1.853051-5.033126 1.948692-4.841843 1.948692-4.483188C1.948692-4.196264 1.912827-4.076712 1.865006-3.861519L.514072 1.518306ZM2.582316-3.730012C2.666002-4.064757 3.000747-4.411457 3.19203-4.578829C3.323537-4.698381 3.718057-5.033126 4.172354-5.033126C4.698381-5.033126 4.937484-4.507098 4.937484-3.88543C4.937484-3.311582 4.60274-1.960648 4.303861-1.338979C4.004981-.6934 3.455044-.119552 2.905106-.119552C2.092154-.119552 1.960648-1.147696 1.960648-1.195517C1.960648-1.231382 1.984558-1.327024 1.996513-1.3868L2.582316-3.730012Z'/&gt;
&lt;path id='eq2-g1-114' d='M4.65056-4.889664C4.27995-4.817933 4.088667-4.554919 4.088667-4.291905C4.088667-4.004981 4.315816-3.90934 4.483188-3.90934C4.817933-3.90934 5.092902-4.196264 5.092902-4.554919C5.092902-4.937484 4.722291-5.272229 4.124533-5.272229C3.646326-5.272229 3.096389-5.057036 2.594271-4.327771C2.510585-4.961395 2.032379-5.272229 1.554172-5.272229C1.08792-5.272229 .848817-4.913574 .705355-4.65056C.502117-4.220174 .32279-3.502864 .32279-3.443088C.32279-3.395268 .37061-3.335492 .454296-3.335492C.549938-3.335492 .561893-3.347447 .633624-3.622416C.812951-4.339726 1.0401-5.033126 1.518306-5.033126C1.80523-5.033126 1.888917-4.829888 1.888917-4.483188C1.888917-4.220174 1.769365-3.753923 1.685679-3.383313L1.350934-2.092154C1.303113-1.865006 1.171606-1.327024 1.111831-1.111831C1.028144-.800996 .896638-.239103 .896638-.179328C.896638-.011955 1.028144 .119552 1.207472 .119552C1.338979 .119552 1.566127 .035866 1.637858-.203238C1.673724-.298879 2.116065-2.10411 2.187796-2.379078C2.247572-2.642092 2.319303-2.893151 2.379078-3.156164C2.426899-3.323537 2.47472-3.514819 2.510585-3.670237C2.546451-3.777833 2.86924-4.363636 3.16812-4.62665C3.311582-4.758157 3.622416-5.033126 4.112578-5.033126C4.303861-5.033126 4.495143-4.99726 4.65056-4.889664Z'/&gt;
&lt;path id='eq2-g1-116' d='M2.402989-4.805978H3.502864C3.730012-4.805978 3.849564-4.805978 3.849564-5.021171C3.849564-5.152677 3.777833-5.152677 3.53873-5.152677H2.486675L2.929016-6.898132C2.976837-7.065504 2.976837-7.089415 2.976837-7.173101C2.976837-7.364384 2.82142-7.47198 2.666002-7.47198C2.570361-7.47198 2.295392-7.436115 2.199751-7.053549L1.733499-5.152677H.609714C.37061-5.152677 .263014-5.152677 .263014-4.925529C.263014-4.805978 .3467-4.805978 .573848-4.805978H1.637858L.848817-1.649813C.753176-1.231382 .71731-1.111831 .71731-.956413C.71731-.394521 1.111831 .119552 1.78132 .119552C2.988792 .119552 3.634371-1.625903 3.634371-1.709589C3.634371-1.78132 3.58655-1.817186 3.514819-1.817186C3.490909-1.817186 3.443088-1.817186 3.419178-1.769365C3.407223-1.75741 3.395268-1.745455 3.311582-1.554172C3.060523-.956413 2.510585-.119552 1.817186-.119552C1.458531-.119552 1.43462-.418431 1.43462-.681445C1.43462-.6934 1.43462-.920548 1.470486-1.06401L2.402989-4.805978Z'/&gt;
&lt;path id='eq2-g1-121' d='M3.144209 1.338979C2.82142 1.793275 2.355168 2.199751 1.769365 2.199751C1.625903 2.199751 1.052055 2.175841 .872727 1.625903C.908593 1.637858 .968369 1.637858 .992279 1.637858C1.350934 1.637858 1.590037 1.327024 1.590037 1.052055S1.362889 .681445 1.183562 .681445C.992279 .681445 .573848 .824907 .573848 1.41071C.573848 2.020423 1.08792 2.438854 1.769365 2.438854C2.964882 2.438854 4.172354 1.338979 4.507098 .011955L5.678705-4.65056C5.69066-4.710336 5.71457-4.782067 5.71457-4.853798C5.71457-5.033126 5.571108-5.152677 5.391781-5.152677C5.284184-5.152677 5.033126-5.104857 4.937484-4.746202L4.052802-1.231382C3.993026-1.016189 3.993026-.992279 3.897385-.860772C3.658281-.526027 3.263761-.119552 2.689913-.119552C2.020423-.119552 1.960648-.777086 1.960648-1.099875C1.960648-1.78132 2.283437-2.701868 2.606227-3.56264C2.737733-3.90934 2.809465-4.076712 2.809465-4.315816C2.809465-4.817933 2.450809-5.272229 1.865006-5.272229C.765131-5.272229 .32279-3.53873 .32279-3.443088C.32279-3.395268 .37061-3.335492 .454296-3.335492C.561893-3.335492 .573848-3.383313 .621669-3.550685C.908593-4.554919 1.362889-5.033126 1.829141-5.033126C1.936737-5.033126 2.139975-5.033126 2.139975-4.638605C2.139975-4.327771 2.008468-3.981071 1.829141-3.526775C1.243337-1.960648 1.243337-1.566127 1.243337-1.279203C1.243337-.143462 2.056289 .119552 2.654047 .119552C3.000747 .119552 3.431133 .011955 3.849564-.430386L3.861519-.418431C3.682192 .286924 3.56264 .753176 3.144209 1.338979Z'/&gt;
&lt;/defs&gt;
&lt;g id='eq2-page1'&gt;
&lt;use x='95.40479' y='-2.988792' xlink:href='#eq2-g1-116'/&gt;
&lt;use x='102.952779' y='-2.988792' xlink:href='#eq2-g2-61'/&gt;
&lt;use x='115.37826' y='-2.988792' xlink:href='#eq2-g2-40'/&gt;
&lt;use x='119.930586' y='-2.988792' xlink:href='#eq2-g1-112'/&gt;
&lt;use x='125.805729' y='-2.988792' xlink:href='#eq2-g1-111'/&gt;
&lt;use x='131.433166' y='-2.988792' xlink:href='#eq2-g1-105'/&gt;
&lt;use x='135.426598' y='-2.988792' xlink:href='#eq2-g1-110'/&gt;
&lt;use x='142.414204' y='-2.988792' xlink:href='#eq2-g1-116'/&gt;
&lt;use x='149.298027' y='-2.988792' xlink:href='#eq2-g0-0'/&gt;
&lt;use x='161.253188' y='-2.988792' xlink:href='#eq2-g1-114'/&gt;
&lt;use x='166.853661' y='-2.988792' xlink:href='#eq2-g1-97'/&gt;
&lt;use x='172.998606' y='-2.988792' xlink:href='#eq2-g1-121'/&gt;
&lt;use x='179.135257' y='-2.988792' xlink:href='#eq2-g1-58'/&gt;
&lt;use x='182.386919' y='-2.988792' xlink:href='#eq2-g1-111'/&gt;
&lt;use x='188.014356' y='-2.988792' xlink:href='#eq2-g1-114'/&gt;
&lt;use x='193.61483' y='-2.988792' xlink:href='#eq2-g1-105'/&gt;
&lt;use x='197.608262' y='-2.988792' xlink:href='#eq2-g1-103'/&gt;
&lt;use x='203.642518' y='-2.988792' xlink:href='#eq2-g1-105'/&gt;
&lt;use x='207.63595' y='-2.988792' xlink:href='#eq2-g1-110'/&gt;
&lt;use x='214.623556' y='-2.988792' xlink:href='#eq2-g2-41'/&gt;
&lt;use x='219.175882' y='-2.988792' xlink:href='#eq2-g1-61'/&gt;
&lt;use x='225.028872' y='-2.988792' xlink:href='#eq2-g1-114'/&gt;
&lt;use x='230.629345' y='-2.988792' xlink:href='#eq2-g1-97'/&gt;
&lt;use x='236.77429' y='-2.988792' xlink:href='#eq2-g1-121'/&gt;
&lt;use x='242.910941' y='-2.988792' xlink:href='#eq2-g1-58'/&gt;
&lt;use x='246.162603' y='-2.988792' xlink:href='#eq2-g1-100'/&gt;
&lt;use x='252.245296' y='-2.988792' xlink:href='#eq2-g1-105'/&gt;
&lt;use x='256.238728' y='-2.988792' xlink:href='#eq2-g1-114'/&gt;
&lt;use x='261.839201' y='-2.988792' xlink:href='#eq2-g1-101'/&gt;
&lt;use x='267.264641' y='-2.988792' xlink:href='#eq2-g1-99'/&gt;
&lt;use x='272.30263' y='-2.988792' xlink:href='#eq2-g1-116'/&gt;
&lt;use x='276.52979' y='-2.988792' xlink:href='#eq2-g1-105'/&gt;
&lt;use x='280.523222' y='-2.988792' xlink:href='#eq2-g1-111'/&gt;
&lt;use x='286.150659' y='-2.988792' xlink:href='#eq2-g1-110'/&gt;
&lt;/g&gt;
&lt;/svg&gt;&lt;/div&gt;
&lt;p&gt;If the point is in the right side of the ray, then the intersection point is the point that is closest to the ray's origin.&lt;/p&gt;
&lt;p&gt;Now, the only thing that we still need to account is, that most of the times, we have 2 intersection points, one going in, and one going out.&lt;/p&gt;
&lt;p&gt;For this we can change the way we use this formulas by instead of using the point, we use the minimum and maximum values of the box.&lt;/p&gt;
&lt;p&gt;If both our t's make sense, then we have an intersection.&lt;/p&gt;
&lt;p&gt;Here is an excerpt taken from the &lt;code&gt;Raycast&lt;/code&gt; class:&lt;/p&gt;
&lt;pre class="m-code"&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;intersects&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cubos&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Raycast&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Ray&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cubos&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;geom&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Box&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;box&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vec3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;corners&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vec3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;corners&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tMinX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tMaxX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tMinY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tMaxY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tMinZ&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tMaxZ&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// find the maximum of the min&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tMin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tMinX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tMaxX&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tMinY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tMaxY&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tMinZ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tMaxZ&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// find the minimum of the max&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tMax&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tMinX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tMaxX&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tMinY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tMaxY&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tMinZ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tMaxZ&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tMax&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tMin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tMax&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-1.0F&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tMin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0F&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tMax&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tMin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id="intersection-with-a-capsule"&gt;
&lt;h5&gt;Intersection with a Capsule&lt;/h5&gt;
&lt;p&gt;The intersection with a capsule is more straight forward than the collision with a box, as we can separate a capsule into 3 parts,
a cylinder and the two spheres at the ends.&lt;/p&gt;
&lt;p&gt;We then can check for a point of intersection by checking if the ray intersects the cylinder, and if it doesn't, we check if it intersects the spheres.&lt;/p&gt;
&lt;p&gt;We can determine both intersections by simply subbing the the ray's equation for x and z in the cylinder and sphere equations, and then solving it for t.&lt;/p&gt;
&lt;p&gt;Code excerpt from raycast.cpp for the cylinder intersection:&lt;/p&gt;
&lt;pre class="m-code"&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;intersects&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cubos&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Raycast&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Ray&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// We are gonna use the quadratic equation made by subbing the ray equation into the cylinder equation&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// The cylinder equation is:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// x^2 + z^2 = r^2&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// The ray equation is:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// x = x0 + t * dx&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// z = z0 + t * dz&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2.0F&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;radius&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;discriminant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;4.0F&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;discriminant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-1.0F&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// no intersection with the cylinder&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;discriminant&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;2.0F&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;discriminant&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;2.0F&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0F&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0F&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-1.0F&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// no valid intersection&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bottom&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-1.0F&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// intersection is outside the finite cylinder&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="spot-light-shadows-tomas7770"&gt;
&lt;h4&gt;Spot Light Shadows &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/tomas-gouveia/"&gt;&amp;#64;tomas7770&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;Our graphics renderer has received a new major feature in this release: shadows!&lt;/p&gt;
&lt;img class="m-image" src="https://cubos.riscadoa.com/images/blog/release/0-3/cover.png" /&gt;
&lt;p&gt;It should go without saying that this feature has a big impact on the visuals of games
developed with Cubos. We've tried it on &lt;em&gt;Scraps vs Zombies&lt;/em&gt; and the result is stunning!
It's an important step towards the kind of appealing graphics that we hope to achieve.&lt;/p&gt;
&lt;p&gt;For the time being, shadows support is limited to spot lights. To enable them, all you need
to do is add a &lt;a href="https://docs.cubos.riscadoa.com/structcubos_1_1engine_1_1SpotShadowCaster.html"&gt;SpotShadowCaster&lt;/a&gt; component to the spot lights for which you want shadows to be cast,
as shown in the &lt;a href="https://github.com/GameDevTecnico/cubos/tree/main/engine/samples/render/shadows"&gt;Shadows sample&lt;/a&gt;.
Both hard and soft shadows are supported, with a configurable &lt;a href="https://docs.cubos.riscadoa.com/structcubos_1_1engine_1_1ShadowCaster.html#a450e1d2c732f1c38403a428eb0536660"&gt;blurRadius&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Behind the scenes, this works by rendering the world from each light's perspective to determine which parts
are occluded, and making these parts unlit. A large texture known as the &amp;quot;shadow atlas&amp;quot; holds this information for
every light in a quadtree structure, reducing expensive texture switching. Finally, soft shadows are implemented
as a post-processing step that effectively blurs out the shadows.
Below is a screenshot of the shadow atlas with 5 spot lights. Lines have been drawn separating
the areas of the atlas reserved for each light.&lt;/p&gt;
&lt;img class="m-image" src="https://cubos.riscadoa.com/images/blog/release/0-3/shadow_atlas.png" /&gt;
&lt;/section&gt;
&lt;section id="initial-ui-plugin-diogomendonc-a"&gt;
&lt;h4&gt;Initial UI Plugin &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/diogo-mendonca/"&gt;&amp;#64;DiogoMendonc-a&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;Cubos now has a UI system!&lt;/p&gt;
&lt;p&gt;Add a &lt;a href="https://docs.cubos.riscadoa.com/structcubos_1_1engine_1_1UICanvas.html"&gt;UICanvas&lt;/a&gt; to your Render Target, and set a &lt;a href="https://docs.cubos.riscadoa.com/structcubos_1_1engine_1_1UIElement.html"&gt;UIElement&lt;/a&gt; as its child. The UIElement will determine where the entity is drawn, and other UI components you add to the entity, such as a UIImage, will determine what it is that is drawn.
For this initial version of the plugin, there are only two types of elements: &lt;a href="https://docs.cubos.riscadoa.com/structcubos_1_1engine_1_1UIColorRect.html"&gt;UIColorRect&lt;/a&gt;, which simply fills the element with a solid colour, and &lt;a href="https://docs.cubos.riscadoa.com/structcubos_1_1engine_1_1UIImage.html"&gt;UIImage&lt;/a&gt;, which draws an image asset.&lt;/p&gt;
&lt;p&gt;To make using the UIElement easier, there are also a number of components meant to dynamically change its size: &lt;a href="https://docs.cubos.riscadoa.com/structcubos_1_1engine_1_1UIHorizontalStretch.html"&gt;UIHorizontalStretch&lt;/a&gt; and &lt;a href="https://docs.cubos.riscadoa.com/structcubos_1_1engine_1_1UIVerticalStretch.html"&gt;UIVerticalStretch&lt;/a&gt; will make the element expand to its parent's size.&lt;/p&gt;
&lt;p&gt;One more problem that was tackled was the question of how to handle different aspect ratios. As it stands, Cubos now has five different settings for how to handle that, that can be read in detail on &lt;a href="https://docs.cubos.riscadoa.com/examples-engine-ui.html"&gt;the sample page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Finally, there is a &lt;a href="https://docs.cubos.riscadoa.com/structcubos_1_1engine_1_1UINativeAspectRatio.html"&gt;UINativeAspectRatio&lt;/a&gt; that, when paired with an UIImage, will ensure that the UIElement will retain the proportions of the original source file.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="on-the-core"&gt;
&lt;h3&gt;On the Core&lt;/h3&gt;
&lt;section id="metrics-roby2014"&gt;
&lt;h4&gt;Metrics &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/roberto-carlos/"&gt;&amp;#64;roby2014&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;We are excited to introduce the new metrics and profiling utilities!
This started becoming a priority since we detected lots of performance issues in the last Game Jam we participated.&lt;/p&gt;
&lt;p&gt;These tools are designed to help track performance and gather valuable insights about code execution and data.&lt;/p&gt;
&lt;p&gt;How it looks:&lt;/p&gt;
&lt;pre class="m-code"&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;compute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;CUBOS_PROFILE&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// after the scope ends, a new metric `compute` will be added, with the duration of this scope&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;myFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;/// simulate profiling loop&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1337&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// simulate frame by calling a function that does work..&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;compute&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// register some metrics, this could be FPS, entities count, ....&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;CUBOS_METRIC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;count&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Currently, metrics can be accessed manually through the singleton class. However, we plan to
integrate these metrics into our editor for a more streamlined experience.&lt;/p&gt;
&lt;p&gt;Learn more about it on our &lt;a href="https://docs.cubos.riscadoa.com/examples-core-metrics.html"&gt;metrics documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="networking-utilities-roby2014"&gt;
&lt;h4&gt;Networking Utilities &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/roberto-carlos/"&gt;&amp;#64;roby2014&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;In the 0.3 release, Cubos finally has networking! This is a big step forward for our engine, bringing
powerful networking utilities such as &lt;a href="https://docs.cubos.riscadoa.com/classcubos_1_1core_1_1net_1_1Address.html"&gt;Address&lt;/a&gt;,
&lt;a href="https://docs.cubos.riscadoa.com/classcubos_1_1core_1_1net_1_1UdpSocket.html"&gt;UdpSocket&lt;/a&gt;, &lt;a href="https://docs.cubos.riscadoa.com/classcubos_1_1core_1_1net_1_1TcpListener.html"&gt;TcpListener&lt;/a&gt;,
and &lt;a href="https://docs.cubos.riscadoa.com/classcubos_1_1core_1_1net_1_1TcpStream.html"&gt;TcpStream&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Creating an UDP client and sending a message is as simple as:&lt;/p&gt;
&lt;pre class="m-code"&gt;&lt;span class="n"&gt;UdpSocket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Address&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;LocalHost&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Hello, I&amp;#39;m a Cubos UDP client!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;strlen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Address&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;server.com&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8081&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Learn more about it on our &lt;a href="https://docs.cubos.riscadoa.com/examples-core-networking.html"&gt;networking documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="next-steps"&gt;
&lt;h2&gt;Next Steps&lt;/h2&gt;
&lt;p&gt;Although this was a smaller release, we managed to get some important features done!
In the next release, which should be out by the end of this month, we're planning to add:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;standalone editor application&lt;/strong&gt;. Our tools are currently integrated into the games themselves which is not ideal.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Audio support&lt;/strong&gt;, as there's no sound at all in the engine right now.&lt;/li&gt;
&lt;li&gt;Actual &lt;strong&gt;voxel collisions&lt;/strong&gt;, as we currently only check the bounding boxes.&lt;/li&gt;
&lt;li&gt;Basic &lt;strong&gt;rigidbody physics&lt;/strong&gt;, with rotation and friction.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Shadows&lt;/strong&gt; for other light types.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tracing and spans&lt;/strong&gt;, for better tracking of program execution.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can check out the full list of stuff we want to get done in the &lt;a href="https://github.com/GameDevTecnico/cubos/milestone/27"&gt;milestone&lt;/a&gt; for the next release.&lt;/p&gt;
&lt;p&gt;We're currently a team of 13 people, and &lt;strong&gt;we're looking to expand&lt;/strong&gt;! If you're interested in joining us, or just want to learn more about the project, join our &lt;a href="https://discord.gg/WjTtcNTRqD"&gt;Discord server&lt;/a&gt;!&lt;/p&gt;
&lt;/section&gt;
</content><category term="Release"/><category term="Release"/></entry><entry><title>Release 0.2</title><link href="https://cubos.riscadoa.com/blog/release-02/" rel="alternate"/><published>2024-05-21T10:00:00+01:00</published><updated>2024-05-21T10:00:00+01:00</updated><author><name>Cubos Team</name></author><id>tag:cubos.riscadoa.com,2024-05-21:/blog/release-02/</id><summary type="html">&lt;p&gt;From ECS observers and fixed-time step support to better editing tools, a new modular rendering pipeline, and the first physics constraints solvers.&lt;/p&gt;
</summary><content type="html">&lt;section id="new-0-2-features"&gt;
&lt;h2&gt;New 0.2 Features&lt;/h2&gt;
&lt;p&gt;Our focus on this release was to continue working on improving and implementing base functionality, such as rendering and physics, and also to improve on the tools available to the developer.
We've compiled here some of the most important changes (if you're curious, you can check out the full changelog in our &lt;a href="https://github.com/GameDevTecnico/cubos/blob/main/CHANGELOG.md"&gt;repository&lt;/a&gt;).&lt;/p&gt;
&lt;section id="on-the-editor"&gt;
&lt;h3&gt;On the Editor&lt;/h3&gt;
&lt;section id="transform-gizmo-upgrades-diogomendonc-a"&gt;
&lt;h4&gt;Transform Gizmo Upgrades &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/diogo-mendonca/"&gt;&amp;#64;DiogoMendonc-a&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;The biggest change was the addition of a rotation gizmo, so now you can rotate entities using your mouse!&lt;/p&gt;
&lt;p&gt;We also added a toggle that allows changing between using global or local space with the Transform Gizmo,
and a new type of gizmo, a &lt;code&gt;Rotated Box&lt;/code&gt;, which, unlike the old boz gizmos, does not need to be axis-aligned.&lt;/p&gt;
&lt;p&gt;Finally, the transform gizmo is now always rendered at the same size, regardless of the selected entity's distance to the camera.
This should hopefully make it easier to use the tool when moving entities either very far away, or very close.&lt;/p&gt;
&lt;img class="m-image" src="https://cubos.riscadoa.com/images/blog/release/0-2/transform_gizmo.gif" /&gt;
&lt;/section&gt;
&lt;section id="world-inspector-overhaul-diogomsmiranda"&gt;
&lt;h4&gt;World Inspector Overhaul &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/diogo-miranda/"&gt;&amp;#64;diogomsmiranda&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;The World inspector has been on our radar for quite some time now, as a tool that could be improved.
This release we particularly aimed on making it better by focusing on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Making it easier to find the entities you are looking for.&lt;/li&gt;
&lt;li&gt;Displaying more information about the entities in the scene.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To tackle the first point we've added a search bar that allows you to filter the entities in the scene, either by their name, or by their components. e.g:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Searching for &amp;quot;player&amp;quot; will show all entities that have &amp;quot;player&amp;quot; in their name.&lt;/li&gt;
&lt;li&gt;Searching for &amp;quot;Transform&amp;quot; will show all entities that have a &lt;code&gt;Transform&lt;/code&gt; component.&lt;/li&gt;
&lt;li&gt;Searching for &amp;quot;player, Transform&amp;quot; will show all entities that have a &lt;code&gt;Transform&lt;/code&gt; component and contain &amp;quot;player&amp;quot; in their name.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To tackle the second point on our list we added an hierarchy view that shows the entities in the scene in a tree-like structure representing the &lt;code&gt;ChildOf&lt;/code&gt; relation between entities.&lt;/p&gt;
&lt;img class="m-image" src="https://cubos.riscadoa.com/images/blog/release/0-2/world_inspector.gif" /&gt;
&lt;/section&gt;
&lt;section id="sub-scene-importing-in-scene-editor-teres4"&gt;
&lt;h4&gt;Sub-scene importing in scene editor &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/teresa-matos/"&gt;&amp;#64;teres4&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;Previously our scene editor was lacking support for importing sub-scenes.
This meant that developers had to manually open the scene file and paste the sub-scene UUID in its import section.
To save time, we've added a popup that shows all the importable sub-scenes, and allows the developer to select the one they want to import.&lt;/p&gt;
&lt;img class="m-image" src="https://cubos.riscadoa.com/images/blog/release/0-2/scene_editor.gif" /&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="on-the-engine"&gt;
&lt;h3&gt;On the Engine&lt;/h3&gt;
&lt;section id="physics-improvements-fallenatlas"&gt;
&lt;h4&gt;Physics Improvements &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/tiago-antunes/"&gt;&amp;#64;fallenatlas&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;This update we introduced the &lt;code&gt;Solver&lt;/code&gt;, which works to satisfy the physics constraints applied to entities (e.g. Spring, Fixed distance between entities, etc.).&lt;/p&gt;
&lt;p&gt;This means that the developers can now give entities any number of constraints, either engine defined or their own, and the solver will handle their expected interaction.
As of now, we have one constraint, internal to the engine, the &lt;code&gt;PenetrationConstraint&lt;/code&gt;, which separates bodies that are inside each other, and comes in to replace our previous collision solving system.&lt;/p&gt;
&lt;p&gt;With the ability to have repeating systems, it was possible to introduce the physics substeps loop, which
will perform the physics update in multiple smaller steps. This is important to increase the convergence rate of the solver and preservation of energy, by reducing the errors caused by approximations of the simulation.&lt;/p&gt;
&lt;p&gt;These changes should lead to more realistic behavior, as well as better consistency between systems with different performance levels.&lt;/p&gt;
&lt;img class="m-image" src="https://cubos.riscadoa.com/images/blog/release/0-2/complex_physics_sample.gif" /&gt;
&lt;/section&gt;
&lt;section id="modular-renderer-riscadoa-tomas7770"&gt;
&lt;h4&gt;Modular Renderer &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/ricardo-antunes/"&gt;&amp;#64;RiscadoA&lt;/a&gt;, &lt;a href="https://cubos.riscadoa.com/blog/author/tomas-gouveia/"&gt;&amp;#64;tomas7770&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;Before this update, our graphics renderer was very monolithic, with a lot of the code being held in a single file. This posed some problems,
namely that if we wanted to implement new rendering methods in the future (e.g. raytracing), we would end up with tons of duplicate code.
It also didn't fit well with our ECS design, since things such as the renderer and its active cameras were just global resources.&lt;/p&gt;
&lt;p&gt;To overcome this, we've restructured the renderer, splitting it into &lt;a href="https://docs.cubos.riscadoa.com/group__render-plugins.html"&gt;several components with their respective plugins&lt;/a&gt;. The most important ones
are perhaps &lt;code&gt;RenderTarget&lt;/code&gt;, representing something that can be drawn to, and &lt;code&gt;PerspectiveCamera&lt;/code&gt;, which draws to render targets using perspective projection.
Entities with these components are related using a &lt;code&gt;DrawsTo&lt;/code&gt; relation. There are also components that individually enable various parts of the renderer,
such as deferred shading, or effects like bloom and SSAO. This separation opens up possibilities for more customizability from the user side,
and makes the renderer code easier to deal with by engine developers.&lt;/p&gt;
&lt;p&gt;We also used the opportunity to optimize the renderer, namely, by allocating a large GPU buffer for all the voxel meshes, which we then split into smaller buckets.
This way, we can draw all the voxel objects with fewer draw calls, and with way less context switches.
One other feature we improved greatly was entity picking - finding out which entity is visible at a given pixel. Previously, enabling it cut the framerate by more than half, which was unacceptable.
By using &lt;a href="https://www.khronos.org/opengl/wiki/Pixel_Buffer_Object"&gt;Pixel Buffers&lt;/a&gt; and double-buffering, we managed to make its performance impact negligible.&lt;/p&gt;
&lt;img class="m-image" src="https://cubos.riscadoa.com/images/blog/release/0-2/scraps_vs_zombies_new_renderer.png" /&gt;
&lt;p&gt;Additionally, we added a tone-mapping pass to the renderer, which makes better use of the HDR color space. It allows us to tune the exposure of the scene, and also to apply effects like bloom and SSAO in a more realistic way.
One side-effect of us changing the color-space is that now the colors in the game are a bit more washed out. We'll have to go back and tweak the colors in the game to make them look good again.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="on-the-core"&gt;
&lt;h3&gt;On the Core&lt;/h3&gt;
&lt;section id="clearer-plugin-dependencies-riscadoa"&gt;
&lt;h4&gt;Clearer Plugin Dependencies &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/ricardo-antunes/"&gt;&amp;#64;RiscadoA&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;One of the main features of &lt;strong&gt;Cubos&lt;/strong&gt; is its plugin system. We structure all of the engine and editor features as plugins, each with its own set of components, systems, and resources.
The developer ultimately chooses which plugins to include in their game, and may also create their own plugins.&lt;/p&gt;
&lt;p&gt;Plugins may depend on each other. One example is the &lt;a href="https://docs.cubos.riscadoa.com/group__physics-plugin.html"&gt;physics plugin&lt;/a&gt;, which depends on the &lt;a href="https://docs.cubos.riscadoa.com/group__collisions-plugin.html"&gt;collisions plugin&lt;/a&gt;.
Previously, when a plugin was included, all of its dependencies were automatically included. It was also possible to include a plugin twice - the second time, the plugin would simply be ignored.&lt;/p&gt;
&lt;p&gt;While this seems useful, this led to some problems. Since a plugin could be included more than once, there isn't a single place where its safe to make decisions about how a given plugin should behave.
This was particularly problematic with the new modular renderer plugins.&lt;/p&gt;
&lt;p&gt;Imagine a scenario where we have two plugins A and B, which implement different rendering methods.
A and B are incompatible. Adding both should be an error, as it's impossible to have both rendering methods active at the same time.
Additionally, A and B both add on a plugin C, and make decisions about how C should behave. If both A and B are included, which one should have the final say?
How do we specify the dependency between them without coupling their code?&lt;/p&gt;
&lt;p&gt;Our solution to this was to distinguish between &lt;em&gt;depending&lt;/em&gt; and &lt;em&gt;including&lt;/em&gt; a plugin. When a plugin X depends on a plugin Y, adding X without Y being present leads to an error.
When a plugin X includes a plugin Y, including X will also include Y. But, if a plugin is included twice, an error occurs.
This way, we get a clean plugin hierarchy, which is easier to reason about:&lt;/p&gt;
&lt;pre class="m-code"&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;myPlugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Cubos&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cubos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;cubos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;renderVoxelsPlugin&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Don&amp;#39;t care about internals, just need the plugin&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;cubos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mySubPlugin&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Include a sub-plugin, which becomes part of my plugin&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;One issue with this solution is that you would now have to manually include all plugins you need when making a game.
Of course, this is not ideal, and thus, we've added a new &lt;a href="https://docs.cubos.riscadoa.com/group__defaults-plugin.html"&gt;defaults plugin&lt;/a&gt; to the engine that includes all the plugins that are necessary for a basic game to run.
If the developer wants to configure the engine in a different way, they can simply write their own alternative defaults plugin.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="observers-riscadoa"&gt;
&lt;h4&gt;Observers &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/ricardo-antunes/"&gt;&amp;#64;RiscadoA&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;Very often while working with &lt;strong&gt;Cubos&lt;/strong&gt;, we find the need to react to the addition and removal of components in entities.
One use case, for example, is setting up the AABB of an entity when we add a collider to it.
Previously, we had to manually implement this logic, for example, by adding a flag to the collider which was initially &lt;code&gt;false&lt;/code&gt;, and having a system initializing all colliders with the flag set to &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To solve this problem in a more elegant way, we added a new special kind of system: &lt;em&gt;observers&lt;/em&gt;. Observers are essentially systems which instead of running on a specific schedule, run immediately after a certain change occurs in the ECS (akin to callbacks).&lt;/p&gt;
&lt;p&gt;We also found another unexpected use for this feature. Complex plugins with lots of components, such as the physics plugin, where previously cumbersome to work with, as all the required components had to be manually added to each entity we wanted physics to apply to.
With observers, we instead now add a single component &lt;code&gt;PhysicsBundle&lt;/code&gt;. An observer picks up this addition, and immediately replaces this component with all of the required components for the physics plugin to work.&lt;/p&gt;
&lt;p&gt;If you're interested in learning more about this feature and ECS in general on our engine, check out our &lt;a href="https://docs.cubos.riscadoa.com/features-ecs.html"&gt;ECS feature guide&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="introducing-inheritance-in-reflection-roby2014"&gt;
&lt;h4&gt;Introducing Inheritance in Reflection &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/roberto-carlos/"&gt;&amp;#64;roby2014&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Cubos&lt;/strong&gt; has a powerful &lt;a href="https://docs.cubos.riscadoa.com/group__core-reflection.html"&gt;reflection system&lt;/a&gt; to examine and interact with a structures and types at runtime
It works by attaching metadata to types, which we call &lt;em&gt;traits&lt;/em&gt;. These traits can be queried at runtime to get information about the type.
For example, we provide a &lt;code&gt;FieldsTrait&lt;/code&gt;, which you can add to a type to expose its fields to the reflection system.&lt;/p&gt;
&lt;p&gt;One thing we were missing was information about inheritance relationships between types.
We've added a new trait, &lt;code&gt;InheritsTrait&lt;/code&gt;, which allows you to specify that a type inherits from another type.&lt;/p&gt;
&lt;p&gt;This will be particularly useful for serialization, as right now we have to manually add the fields of the base class to the derived class. Now, serializers can check if this trait is present and fallback to the base class if necessary.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="repeating-systems-and-fixed-step-updates-joaomanita"&gt;
&lt;h4&gt;Repeating Systems and Fixed-Step Updates &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/joao-manita/"&gt;&amp;#64;joaomanita&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;Certain plugins, like the physics plugin, required some of their systems to run multiple times per frame so that they could make more accurate
aproximations. In addition, some of them need to be executed in ordered groups. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The integration system needs to run before the velocity update system.&lt;/li&gt;
&lt;li&gt;The velocity update system needs to run before the force clear system.&lt;/li&gt;
&lt;li&gt;The force clear system needs to run before the impulse clear system.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To allow repeating groups such as these, we added a new feature to the ECS tags: the repeat while modifier. This makes the systems tagged by it repeat until a certain condition becomes false.&lt;/p&gt;
&lt;pre class="m-code"&gt;&lt;span class="n"&gt;cubos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;groupTag&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;repeatWhile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myCondition&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;cubos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;integrate physics&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;tagged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;groupTag&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;cubos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;update velocity&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;tagged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;groupTag&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;cubos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;clear forces&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;tagged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;groupTag&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Its also possible to make repeating subgroups by tagging the subgroup with the parent tag.&lt;/p&gt;
&lt;pre class="m-code"&gt;&lt;span class="n"&gt;cubos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subgroupTag&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;tagged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;groupTag&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;repeatWhile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myOtherCondition&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;This way the subgroup's systems will repeat a total of n x m times, where n is the number of times the parent tag repeats and m is the number of times the subgroup tag repeats.&lt;/p&gt;
&lt;p&gt;With this implemented, it was easy to implement the fixed-step plugin on the engine side. It simply adds a tag that makes systems repeat as needed according to
the &lt;code&gt;DeltaTime&lt;/code&gt; passed, avoiding variance due to different frame rates and more/less powerful PCs.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="moving-away-from-the-old-serialization-dacops"&gt;
&lt;h4&gt;Moving Away from the Old Serialization &lt;span class="m-text m-dim author-dim classifier"&gt;(&lt;a href="https://cubos.riscadoa.com/blog/author/david-pires/"&gt;&amp;#64;Dacops&lt;/a&gt;)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;a href="https://docs.cubos.riscadoa.com/group__core-data-ser.html"&gt;Serialization&lt;/a&gt; is a crucial part of the game engine that allows for the saving of any Cubos game components as well as then loading them in.
Previously, serialization was done through a series of functions, both for reading and writing, that could be overloaded for each type.
On the previous (and first) release, we introduced a reflection system, that allowed for the inspection of types at runtime. This was an essential step to make the inspectors on the editor side work.&lt;/p&gt;
&lt;p&gt;But with this new system, we now had two sources of truth for the types, the reflection system and the serialization system.
To solve this, we decided to change the serialization system to use the reflection system, and thus, not force the developer to write serialization code for each type.&lt;/p&gt;
&lt;p&gt;On this release, we've finally finished this transition, by replacing serialization by direct stream manipulation in places where performance was more of a concern, such as voxel object saving/loading; and by replacing the serialization methods by reflection in other places, such as the input bindings.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="next-steps"&gt;
&lt;h2&gt;Next Steps&lt;/h2&gt;
&lt;p&gt;We're very happy with the progress we've made on this release. The engine is becoming more and more powerful, and we were able to create a full game with it in a week!&lt;/p&gt;
&lt;p&gt;For the next release, which should be out in July, we'll be focusing on expanding the engine's capabilities, as it is currently missing some key features, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;standalone editor application&lt;/strong&gt;. Our tools are currently integrated into the games themselves which is not ideal.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Audio support&lt;/strong&gt;, as there's no sound at all in the engine right now.&lt;/li&gt;
&lt;li&gt;An initial &lt;strong&gt;UI plugin&lt;/strong&gt;, which can render images, text and handle buttons.&lt;/li&gt;
&lt;li&gt;Actual &lt;strong&gt;voxel collisions&lt;/strong&gt;, as we currently only check the bounding boxes.&lt;/li&gt;
&lt;li&gt;Basic &lt;strong&gt;rigidbody physics&lt;/strong&gt;, with rotation and friction.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Shadows, transparency&lt;/strong&gt; and other rendering features.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Raycasting&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Networking&lt;/strong&gt; utilities, to allow for online multiplayer games.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Web-support&lt;/strong&gt;, so that games can be played in the browser.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C API&lt;/strong&gt;, so that we can use the engine from other languages (scripts!).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Better editor tools&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can check out the full list of stuff we want to get done in the &lt;a href="https://github.com/GameDevTecnico/cubos/milestone/26"&gt;milestone&lt;/a&gt; for the next release.&lt;/p&gt;
&lt;p&gt;We're currently a team of 10 people, and &lt;strong&gt;we're looking to expand&lt;/strong&gt;! If you're interested in joining us, or just want to learn more about the project, join our &lt;a href="https://discord.gg/WjTtcNTRqD"&gt;Discord server&lt;/a&gt;!&lt;/p&gt;
&lt;/section&gt;
</content><category term="Release"/><category term="Release"/></entry></feed>