<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>C++ on jairrs</title><link>https://jairsantana.com/tags/c++/</link><description>Recent content in C++ on jairrs</description><generator>Hugo -- 0.156.0</generator><language>en-us</language><atom:link href="https://jairsantana.com/tags/c++/index.xml" rel="self" type="application/rss+xml"/><item><title>Computer Graphics: Curves, Animation, and Rendering</title><link>https://jairsantana.com/portfolio/computer-graphics/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://jairsantana.com/portfolio/computer-graphics/</guid><description>Spline modeling, skeletal deformation, cloth simulation, ray tracing, and shadow mapping in C++ and OpenGL.</description><content:encoded><![CDATA[<p>For MIT&rsquo;s 6.4400 Computer Graphics course, I implemented a series of assignments covering spline curves and surfaces, skeletal animation, physically-based simulation, ray tracing, and shadow mapping. Most of the work used GLOO, the course&rsquo;s lightweight C++ OpenGL framework, with GLM for vector and matrix operations.</p>
<p>Here&rsquo;s a small overview of what I learned.</p>
<h2 id="modeling-curves-and-surfaces">Modeling Curves and Surfaces</h2>
<p>In Assignment 1, I implemented cubic Bézier and B-Spline curves, conversion between their control-point representations, and bicubic tensor product patches. This gave me a better understanding of non-polygonal representations for surfaces. Since the patches are continuous and differentiable, we can easily get the normal for lighting as well.</p>
<h2 id="attaching-a-mesh-to-a-skeleton">Attaching a Mesh to a Skeleton</h2>
<p>Assignment 2 covered hierarchical transforms and skeletal subspace deformation, also called linear blend skinning. I built a node hierarchy and attached a mesh using per-vertex joint weights. Rotating a parent joint carries its descendants with it, while the weights let a vertex respond to several joints at once.</p>
<p>The approach is to first move a vertex from the character&rsquo;s bind pose into a joint&rsquo;s bind-pose coordinate frame, then move it back using that joint&rsquo;s current transform. I also passed accumulated transforms down the scene tree when collecting objects for rendering, avoiding repeated walks up the hierarchy. I believe this is very similar (if not identical) to how videogames handle object rendering trees.</p>
<details class="article-details">
    <summary>Code: one joint&#39;s contribution to a vertex</summary>
    <div class="article-details-content">
        <div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span>glm<span style="color:#ff7b72;font-weight:bold">::</span>mat4x4 <span style="color:#ff7b72;font-weight:bold">&amp;</span>bind_pose_joint_to_character_inverse_ <span style="color:#ff7b72;font-weight:bold">=</span> Bs_[j];
</span></span><span style="display:flex;"><span>glm<span style="color:#ff7b72;font-weight:bold">::</span>mat4x4 <span style="color:#ff7b72;font-weight:bold">&amp;</span>joint_to_character <span style="color:#ff7b72;font-weight:bold">=</span> joint_to_character_matrices[j];
</span></span><span style="display:flex;"><span>glm<span style="color:#ff7b72;font-weight:bold">::</span>vec4 position_contribution <span style="color:#ff7b72;font-weight:bold">=</span> (attachment_weights_[i][j] <span style="color:#ff7b72;font-weight:bold">*</span>
</span></span><span style="display:flex;"><span>joint_to_character <span style="color:#ff7b72;font-weight:bold">*</span> bind_pose_joint_to_character_inverse_ <span style="color:#ff7b72;font-weight:bold">*</span> bind_pose_position);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>new_positions<span style="color:#ff7b72;font-weight:bold">-&gt;</span>at(i) <span style="color:#ff7b72;font-weight:bold">+=</span> glm<span style="color:#ff7b72;font-weight:bold">::</span>vec3(position_contribution);
</span></span></code></pre></div><p>Summing these weighted contributions gives the deformed vertex position.</p>

    </div>
</details>

<h2 id="simulating-motion-with-particles-and-springs">Simulating Motion with Particles and Springs</h2>
<p>For Assignment 3, I implemented forward Euler, explicit trapezoidal, and fourth-order Runge–Kutta integration, then used them for circular motion, a spring-connected pendulum, and wireframe cloth. The particle system combines gravity, drag, and spring forces. The integrator then advances its positions and velocities over time.</p>
<p>The cloth is a grid with structural springs connecting neighbors, shear springs connecting diagonals, and flex springs spanning two grid edges. These resist stretching, diagonal collapse, and bending. This was more of a programming exercise, but it was still cool to see how to make a cloth simulation.</p>
<h2 id="rendering-with-rays">Rendering with Rays</h2>
<p>We were tasked with building a CPU ray tracer. I implemented sphere, plane, and triangle intersections, Phong lighting, shadow rays, and recursive reflections. Rays are transformed into object space for intersection, while normals return to world space using the inverse transpose of the object&rsquo;s transform.</p>
<details class="article-details">
    <summary>Code: tracing a reflection</summary>
    <div class="article-details-content">
        <div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#ff7b72">if</span>(bounces <span style="color:#ff7b72;font-weight:bold">&gt;</span> <span style="color:#a5d6ff">0</span>) {
</span></span><span style="display:flex;"><span>  <span style="color:#8b949e;font-style:italic">// ray bounces
</span></span></span><span style="display:flex;"><span>  <span style="color:#ff7b72">const</span> glm<span style="color:#ff7b72;font-weight:bold">::</span>vec3 ray_bounce_origin    <span style="color:#ff7b72;font-weight:bold">=</span> hit_position <span style="color:#ff7b72;font-weight:bold">+</span> EPSILON <span style="color:#ff7b72;font-weight:bold">*</span> eye_reflection;
</span></span><span style="display:flex;"><span>  <span style="color:#ff7b72">const</span> glm<span style="color:#ff7b72;font-weight:bold">::</span>vec3 ray_bounce_direction <span style="color:#ff7b72;font-weight:bold">=</span> eye_reflection;
</span></span><span style="display:flex;"><span>  <span style="color:#ff7b72">const</span> Ray       <span style="color:#d2a8ff;font-weight:bold">ray_bounce</span>(ray_bounce_origin, ray_bounce_direction);
</span></span><span style="display:flex;"><span>  HitRecord bounce_record <span style="color:#ff7b72;font-weight:bold">=</span> HitRecord();
</span></span><span style="display:flex;"><span>  color <span style="color:#ff7b72;font-weight:bold">+=</span> material_specular_color <span style="color:#ff7b72;font-weight:bold">*</span> TraceRay(ray_bounce, bounces <span style="color:#ff7b72;font-weight:bold">-</span> <span style="color:#a5d6ff">1</span>, bounce_record);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p><code>eye_reflection</code> is the reflected viewing-ray direction. The small offset keeps the new ray from immediately intersecting the surface it just left.</p>

    </div>
</details>

<h2 id="casting-shadows-in-opengl">Casting Shadows in OpenGL</h2>
<p>Assignment 5 involved texture mapping and shadows from a directional light. I rendered the scene from the light&rsquo;s viewpoint into a depth texture, then sampled that texture while shading the camera&rsquo;s view. If a fragment is farther from the light than the stored depth, another surface is blocking it.</p>
<p>This involved framebuffer objects, texture sampling, coordinate transforms, and GLSL. A small depth bias helps prevent a surface from incorrectly shadowing itself because of numerical error.</p>
<details class="article-details">
    <summary>Code: comparing against the shadow map</summary>
    <div class="article-details-content">
        <div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-glsl" data-lang="glsl"><span style="display:flex;"><span><span style="color:#ff7b72">vec3</span> proj_coords <span style="color:#ff7b72;font-weight:bold">=</span> (world_to_light_ndc_matrix <span style="color:#ff7b72;font-weight:bold">*</span> <span style="color:#ff7b72">vec4</span>(world_position, <span style="color:#a5d6ff">1.0</span>)).xyz;
</span></span><span style="display:flex;"><span>proj_coords <span style="color:#ff7b72;font-weight:bold">=</span> proj_coords <span style="color:#ff7b72;font-weight:bold">*</span> <span style="color:#a5d6ff">0.5</span> <span style="color:#ff7b72;font-weight:bold">+</span> <span style="color:#a5d6ff">0.5</span>;
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">float</span> this_depth     <span style="color:#ff7b72;font-weight:bold">=</span> proj_coords.z;
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">float</span> occluder_depth <span style="color:#ff7b72;font-weight:bold">=</span> texture(shadow_texture, proj_coords.xy).r;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">float</span> bias <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">0.005</span>;
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">if</span>(occluder_depth <span style="color:#ff7b72;font-weight:bold">&lt;</span> this_depth <span style="color:#ff7b72;font-weight:bold">-</span> bias) {
</span></span><span style="display:flex;"><span>    <span style="color:#ff7b72">return</span> <span style="color:#ff7b72">vec3</span>(<span style="color:#a5d6ff">0.0</span>, <span style="color:#a5d6ff">0.0</span>, <span style="color:#a5d6ff">0.0</span>);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div>
    </div>
</details>

<p>These assignments preceded my final project, <a href="/posts/grass/">emulating Ghost of Tsushima&rsquo;s procedural grass in Godot</a>.</p>
]]></content:encoded></item></channel></rss>