




[{"content":"","date":"29 June 2026","externalUrl":null,"permalink":"/blog/","section":"Blogs","summary":"","title":"Blogs","type":"blog"},{"content":"I\u0026rsquo;ve been following Iñigo Quilez\u0026rsquo;s masterclass \u0026ldquo;Live Coding \u0026lsquo;Happy Jumping\u0026rsquo;\u0026rdquo;, where he implements a raymarching shader in ShaderToy that generates a scene with a jumping monster walking across a peculiar terrain. For him it was an animation exercise, since he applies principles like squash and stretch.\nFor me, however, it\u0026rsquo;s an opportunity to learn how these three-dimensional scenes are built using shaders, without 3D models, just math and code. With this article I try to expand on some concepts to make them clearer and dig a bit deeper into the subject.\nWatch the \u0026ldquo;Happy Jumping\u0026rdquo; shader on ShaderToy\nRaymarching\rAccording to Iñigo Quilez, raymarching can be understood as a technique for exploring a three-dimensional scene with rays. Each pixel on the screen generates a ray that travels into the virtual space and searches for the surfaces present in the scene. With raymarching, the scene is described through distances instead of exactly calculating the intersection between a ray and the geometry (ray tracing). The algorithm advances iteratively along the ray using the estimated distance to the nearest surface.\nAt each iteration a Signed Distance Function (SDF) is evaluated, a function that returns the signed distance to the nearest surface. This value determines how far the ray can safely advance without passing through any object. When the surface is far away, the steps can be large; as the ray gets closer to an object, the increments progressively shrink, increasing the precision of the calculation.\nFrom GPU Gems 2: Chapter 8.\nThanks to this mechanism, it\u0026rsquo;s possible to represent complex scenes defined solely through mathematical functions, without the need for meshes, vertices, or traditional geometric structures.\n// This normalize the coordinates from (-aspectRatio,-1) to (aspectRatio, 1) vec2 p = (2.0*(fragCoord+offset)-iResolution.xy) / iResolution.y; vec3 ro = vec3(0.0,0.0,2.0); vec3 rd = normalize(vec3(p,-1.5)); // if ray doesn\u0026#39;t hit anything value -1 vec4 res = vec4(-1.0, -1.0, 0.0,1.0); float t = 0.0; for(int i = 0; i \u0026lt; 128; ++i) { vec3 pos = ro + t* rd; // map function will return a distance that is secure to advance vec4 h = map(pos,atime); t+=h.x; } Raymarching pseudocode\nNow then, how is that maximum advance distance calculated without passing through the different objects? There\u0026rsquo;s no single answer: depending on the type of object, there are different formulas. A sphere would be an example of a simple case:\nDemonstration of the h calculation\nThe maximum distance (h) we can advance without passing through the sphere is the distance between the ray origin and the sphere\u0026rsquo;s center, minus its radius.\nWith this we can already start drawing something: as soon as we know we\u0026rsquo;ve hit the sphere, we can show it on screen and even start lighting it.\nFirst render of a sphere with raymarching\nCalculating normals\rTo calculate the scene\u0026rsquo;s lighting, we first need to calculate the normals of the objects the ray collides with. Once we know at what distance t the collision happens, we can find the exact point on the surface, and from there calculate the normal.\nvec3 pos = ro + t*rd; vec3 nor = calcNormal( pos, time ); Since the map() function is continuous, the direction in which the distance changes fastest (its gradient) coincides with the surface normal. To approximate that gradient, we take the collision point and shift it slightly along each axis (x, y, z), calculating the difference in distance between shifting the point to one side and to the other (central finite differences). The normalized result gives us the direction of the normal.\nvec3 calcNormal( in vec3 pos, float time ) { float e = 0.0001; // small offset float dx = map( pos + vec3(e,0,0), time ).x - map( pos - vec3(e,0,0), time ).x; float dy = map( pos + vec3(0,e,0), time ).x - map( pos - vec3(0,e,0), time ).x; float dz = map( pos + vec3(0,0,e), time ).x - map( pos - vec3(0,0,e), time ).x; return normalize( vec3(dx, dy, dz) ); } Central finite difference: instead of comparing the collision point with a single shifted point, we compare two points placed symmetrically on either side (pos+e and pos-e). This gives a more accurate approximation of the derivative than looking to only one side, since it averages the variation in both directions.\nLighting calculation\rSun Diffuse\rTo calculate how much direct sunlight a point on the surface receives, we use the object\u0026rsquo;s normal and the direction toward the light (the sun, in this case). We calculate the dot product between both vectors; since both are unit vectors (normalized), the result is directly the cosine of the angle between them.\nThis cosine is what\u0026rsquo;s known as Lambert\u0026rsquo;s cosine law: the more aligned the normal is with the light direction (angle close to 0°), the more light the surface receives (cosine close to 1); the more obliquely the light hits (angle close to 90°), the less light reaches it (cosine close to 0). This simulates how the same amount of light gets \u0026ldquo;spread\u0026rdquo; over more or less surface depending on the angle of incidence.\nvec3 sun_dir = normalize(vec3(0.6, 0.35, 0.5)); float sun_dif = clamp(dot(sun_dir, normal), 0.0, 1.0); We do clamp(..., 0.0, 1.0) because, if the angle exceeds 90° (the surface faces away from the sun), the cosine becomes negative — and a negative amount of light doesn\u0026rsquo;t make physical sense. Clamping the value between 0 and 1 ensures that those surfaces simply receive no direct sunlight (they\u0026rsquo;re in self-shadow), instead of incorrectly \u0026ldquo;subtracting\u0026rdquo; light.\nSky Diffuse \u0026amp; Bounce Diffuse\rTo give the scene sky lighting and ground lighting (bounced light), we use the same technique as with sunlight.\nWe take the dot product of the normal with the vertical vector: positive (0,1,0) for the sky, negative (0,-1,0) for the ground bounce. We also remap the values so they range from 0 to 1, since the dot product returns a value between -1 and 1. In sky_dif we use 0.5 + 0.5*x, which splits the range symmetrically (half and half); in bou_dif we use 0.1 + 0.9*x, a different mix that gives more weight to the dot product (a stronger bounce when the normal faces directly toward the ground) and less weight to a constant base value. Finally, the result is clamped so it doesn\u0026rsquo;t fall outside the [0.0, 1.0] range.\nfloat sky_dif = clamp(0.5 + 0.5*dot(normal, vec3(0.0, 1.0, 0.0)), 0.0, 1.0); float bou_dif = clamp(0.1 + 0.9*dot(normal, vec3(0.0, -1.0, 0.0)), 0.0, 1.0); This can be simplified, since multiplying by a unit vector that only has one active component simply \u0026ldquo;extracts\u0026rdquo; that component. So we can use normal.y directly instead of doing the dot product:\nfloat sky_dif = clamp(0.5 + 0.5*normal.y, 0.0, 1.0); float bou_dif = clamp(0.1 - 0.9*normal.y, 0.0, 1.0); Hard Shadows\rThe idea of calculating shadows in raymarching is fairly simple. We reuse the same castRay function we used for the camera ray, but now we cast the ray from the object\u0026rsquo;s surface (slightly offset along the normal, so it doesn\u0026rsquo;t collide with itself due to precision errors) toward the light. If that ray hits something before reaching the light source, the original point is in shadow. float sun_sha = step(castRay(pos + 0.001*nor, sun_lig, time), 0.0); step(value, 0.0) — the step(edge, x) function returns 0.0 if x \u0026lt; edge, and 1.0 if x \u0026gt;= edge. Here it\u0026rsquo;s used \u0026ldquo;backwards\u0026rdquo; from how it\u0026rsquo;s usually read: step(castRay(...), 0.0) compares 0.0 against the result of castRay. Since in this simplified version castRay returns -1.0 when there\u0026rsquo;s no hit:\nIf there\u0026rsquo;s no hit → castRay(...) = -1.0 → step(-1.0, 0.0) = 1.0 (0.0 ≥ -1.0) → no shadow, full light. If there\u0026rsquo;s a hit (it collides with something) → castRay(...) is a positive distance (e.g. 3.5) → step(3.5, 0.0) = 0.0 (0.0 \u0026lt; 3.5) → full shadow. Occlusion calculation\rThis function simulates a very subtle but important effect for realism: areas where nearby geometry surrounds a point (corners, folds, gaps between shapes) receive less ambient light, because part of that light gets blocked by the neighboring objects themselves. It\u0026rsquo;s what makes a character\u0026rsquo;s armpits, or the gap between two fingers, look slightly darker even without a shadow cast by the sun.\nfloat h = 0.01 + 0.11*float(i)/4.0; vec3 opos = pos + h*nor;\rfloat d = map( opos, time ).x;\rocc += (h-d)*sca; For each of the 5 iterations, we take the surface point (pos) and move a distance h along the normal (nor) — that is, we move perpendicularly outward from the object. If there were nothing else nearby (a fully convex, unobstructed surface), the real distance to any other object at that point (d, obtained from map()) would be exactly h — because there\u0026rsquo;s no obstacle interfering.\nBut if there\u0026rsquo;s neighboring geometry nearby (a corner, a fold), the real distance d will be smaller than h, because something is in the way before that expected distance. The difference h - d measures exactly that: how much \u0026ldquo;closer than expected\u0026rdquo; there is surface there — the more neighboring geometry there is, the greater this difference.\nreturn clamp( 1.0 - 2.0*occ, 0.0, 1.0 ); occ accumulates the weighted (h-d) differences: the higher occ is, the more \u0026ldquo;enclosed\u0026rdquo; the point is by neighboring geometry. By doing 1.0 - 2.0*occ, we invert the scale: if occ is high (a lot of occlusion), the result approaches 0 (little ambient light); if occ is low or zero (unobstructed surface), the result approaches 1 (full ambient light). The clamp ensures the result always stays in the [0, 1] range, since the multiplication by 2.0 is an arbitrary factor to amplify the effect (an artistic adjustment, not a physical one) and could push the value out of range.\nCamera (Look-at)\rTo build a camera that always looks at a fixed point. A target is defined, and from there the camera\u0026rsquo;s position (which will also be the ray origin, ro).\nWith the target and the origin we can define the \u0026ldquo;forward\u0026rdquo; vector (ww), normalized: it\u0026rsquo;s simply the direction from ro toward target.\nTo generate the \u0026ldquo;right\u0026rdquo; vector (uu), we take the cross product of the forward vector and the world\u0026rsquo;s vertical vector. The cross product between two vectors gives a third vector perpendicular to both. By doing cross(ww, vec3(0,1,0)) (forward × world-up), we get a vector perpendicular both to \u0026ldquo;where the camera is looking\u0026rdquo; and to the world\u0026rsquo;s vertical axis — which is exactly the camera\u0026rsquo;s \u0026ldquo;right\u0026rdquo; direction.\nOnce we have the forward and right vectors, we repeat the process to get the camera\u0026rsquo;s actual \u0026ldquo;up\u0026rdquo; vector (vv). We can\u0026rsquo;t simply reuse vec3(0,1,0) as up, because if the camera looks up or down, that \u0026ldquo;world up\u0026rdquo; would no longer be perpendicular to the other two axes. That\u0026rsquo;s why we recompute it with cross(uu, ww), ensuring the three vectors form a perfectly orthogonal basis with each other.\nvec3 target = vec3(0.0, 0.75, 0.4);\r// ray origin\rvec3 ro = target + vec3(1.5 * sin(an),-.1,1.5 * cos(an));\rvec3 ww = normalize(target - ro);\rvec3 uu = normalize(cross(ww, vec3(0,1,0)));\rvec3 vv = normalize(cross(uu,ww)); These vectors form the basis for building the direction of each pixel\u0026rsquo;s ray:\n// This normalize the coordinates from [-aspectRatio,-1] to [aspectRatio, 1]\rvec2 p = (2.0*(fragCoord+offset) - iResolution.xy) / iResolution.y;\rvec3 rd = normalize(p.x*uu + p.y*vv + 1.8*ww); Here p.x and p.y are the normalized pixel coordinates on screen: p.y ranges from -1 to 1, while p.x ranges from -aspectRatio to aspectRatio (where aspectRatio is the screen\u0026rsquo;s width divided by its height). These coordinates are combined with the camera\u0026rsquo;s uu (right), vv (up), and ww (forward) axes to build the ray\u0026rsquo;s direction in world space — that is, \u0026ldquo;how much I deviate right/up from the center of the view, and how much I advance forward.\u0026rdquo; The 1.8 multiplying ww controls the field of view (FOV): the larger that number, the more \u0026ldquo;zoom\u0026rdquo; (narrower field of view); the smaller, the wider the angle (broader FOV).\nSimple scene\rThis is the final result: Iñigo Quilez\u0026rsquo;s shader with a basic scene that brings together the elements we\u0026rsquo;ve covered — the raymarching loop, the normal calculation, and the lighting combining sun, sky, bounce, and shadows.\nIñigo Quilez\u0026rsquo;s shader on ShaderToy\n","date":"29 June 2026","externalUrl":null,"permalink":"/blog/0_raymarching/","section":"Blogs","summary":"","title":"Introduction to Raymarching","type":"blog"},{"content":"\rGame Developer specializing in C++ and real-time rendering, with a solid foundation in game engine architecture and hands-on experience in 3D graphics programming. I hold a Bachelor\u0026rsquo;s in Game Design and Development from UPC and a Master\u0026rsquo;s in Graphics Computation, Simulation, and VR at U-TAD. While my primary focus is programming in C/C++, I have also worked with C#, Python, Dart, and JavaScript. I have experience with libraries like OpenGL and SDL and have built my own custom game engine, incorporating features such as skeletal animation and frustum culling using spatial partitioning. I’ve also contributed to collaborative projects using Unity, including multiple game jams and award-winning experiences. I am passionate about continuous learning, collaborating with diverse teams, and exploring the cutting edge of interactive technology.\nDownload CV ","date":"26 October 2025","externalUrl":null,"permalink":"/about-me/","section":"Main","summary":"","title":"About me","type":"page"},{"content":"I’m a software engineer specialized in real-time graphics and game development, with experience working both in the entertainment and interactive technology sectors. Over the past years I’ve contributed to projects ranging from slot machine software developed in C++ to medical visualization tools and interactive applications built in Unity. My work spans gameplay systems, rendering features, UI development, internal tools, and performance-focused programming. I enjoy creating robust technical solutions, designing efficient workflows, and contributing to multidisciplinary teams with a strong focus on clarity and maintainability.\n","date":"26 October 2025","externalUrl":null,"permalink":"/resume/","section":"Resume","summary":"","title":"Resume","type":"resume"},{"content":"Game Developer \u0026amp; Technical Artist\n","date":"13 June 2022","externalUrl":null,"permalink":"/","section":"Main","summary":"","title":"Main","type":"page"},{"content":"","date":"25 June 2021","externalUrl":null,"permalink":"/tags/c++/","section":"Tags","summary":"","title":"C++","type":"tags"},{"content":"","date":"25 June 2021","externalUrl":null,"permalink":"/tags/engine-development/","section":"Tags","summary":"","title":"Engine Development","type":"tags"},{"content":"","date":"25 June 2021","externalUrl":null,"permalink":"/tags/graphics-programming/","section":"Tags","summary":"","title":"Graphics Programming","type":"tags"},{"content":"","date":"25 June 2021","externalUrl":null,"permalink":"/tags/opengl/","section":"Tags","summary":"","title":"OpenGL","type":"tags"},{"content":"","date":"25 June 2021","externalUrl":null,"permalink":"/projects/","section":"Projects","summary":"","title":"Projects","type":"projects"},{"content":"","date":"25 June 2021","externalUrl":null,"permalink":"/tags/real-time-rendering/","section":"Tags","summary":"","title":"Real-Time Rendering","type":"tags"},{"content":"\rOverview\r#\rShadow is a real-time rendering library that implements several core techniques used in modern videogame engines. It is written entirely in C++ using OpenGL, and was developed as my Final Degree Project.\nGitHub Repository About the Project\r#\rThe goal of Shadow was to study and implement real-time rendering techniques from the ground up, focusing on engine-level graphics systems rather than using pre-built frameworks or shading pipelines.\nThe engine follows a Deferred Rendering pipeline and includes multiple post-processing and shading features.\nLibrary Features\r#\rI designed and implemented:\nDeferred Rendering pipeline G-Buffer layout and multi-pass architecture Physically-Based Rendering (PBR) Metalness/Roughness workflow Screen Space Ambient Occlusion (SSAO) Bloom post-processing pipeline Normal Mapping Tangent-space basis (TBN) generation Resource management system ImGui debugging / visualization tools Scene rendering loop and material system Rendering Pipeline\r#\rShadow uses a Deferred Shading workflow to support multiple dynamic lights efficiently.\nMaterial data is stored in a G-Buffer, then lighting is computed in a separate pass.\nVisual Output\r#\rVersion Log\r#\rv0.1\r#\rEngine foundation (Windowing, Input System, Resource Loading) Skybox renderer G-Buffer initialization Base Deferred Shading implementation v1.0 (Final Degree Project Completion)\r#\rPhysically-Based Rendering (PBR) SSAO Pass Bloom Post-Processing Normal Mapping Pipeline ","date":"25 June 2021","externalUrl":null,"permalink":"/projects/shadow-graphics-library/","section":"Projects","summary":"","title":"Shadow Graphics Library","type":"projects"},{"content":"","date":"25 June 2021","externalUrl":null,"permalink":"/tags/","section":"Tags","summary":"","title":"Tags","type":"tags"},{"content":"","date":"29 December 2020","externalUrl":null,"permalink":"/tags/c%23/","section":"Tags","summary":"","title":"C#","type":"tags"},{"content":"","date":"29 December 2020","externalUrl":null,"permalink":"/tags/game-jam/","section":"Tags","summary":"","title":"Game Jam","type":"tags"},{"content":"\rOverview\r#\rK.U.B.O is a puzzle-platformer created during the CITM-UPC University Game Jam, where the theme was Paradox.\nOur team decided to explore this concept through forced perspective and illusion-based level design.\nYou play as a small cube trapped in a 2D world. However, by pressing the red button, the environment briefly reveals its true 3D structure, exposing perspective tricks and hidden paths needed to solve each level.\nThis dual-view mechanic—2D gameplay with momentary 3D reveals—became the central paradox around which the entire game was built.\nGitHub Repository\rMy Contribution\r#\rGameplay programming Level design support Puzzle mechanics involving perspective shifts General debugging and polishing 🏆 Award: Best Game\r#\rK.U.B.O won the Best Game Award at the CITM-UPC Game Jam.\nThe jury highlighted that it was the project that best captured and integrated the jam’s theme: “Paradox”, offering a clever and consistent use of perspective-based mechanics.\nCredits\r#\rAlex Morales\nGitHub: Alexmg99\nYessica Servin\nGitHub: YessicaSD\nPol Vázquez\nGitHub: Amade128\nHimar Bravo\nGitHub: Himar33\nMarc Pavón Llop\nGitHub: Mackitus\n","date":"29 December 2020","externalUrl":null,"permalink":"/projects/kubo/","section":"Projects","summary":"","title":"K.U.B.O - Game Jam","type":"projects"},{"content":"","date":"29 December 2020","externalUrl":null,"permalink":"/tags/unity/","section":"Tags","summary":"","title":"Unity","type":"tags"},{"content":"","date":"12 June 2020","externalUrl":null,"permalink":"/tags/customengine/","section":"Tags","summary":"","title":"CustomEngine","type":"tags"},{"content":"\rOverview\r#\rThe Witcher: A Bard\u0026rsquo;s Tale is a cooperative beat-\u0026rsquo;em-up / hack-and-slash adventure. Players control Geralt of Rivia and Yennefer of Vengerberg as they fight to rescue Ciri.\nPlay About the project\r#\rThis is a university group project built with a custom C++ engine and OpenGL. The design focuses on responsive combat, cinematic boss encounters, and polished presentation. My work spans graphics programming, gameplay tooling, and content creation.\nMy individual contributions\r#\rGPU skinning (vertex shader skinning) Subtitles system (JSON import + typewriter effect) Boss presentation (cinematic camera movement) Dummy enemy for combat testing Dissolve shader effects Main character models and 3D assets Scene lighting HUD design and menu polish Skinning with shaders\r#\rTo improve runtime performance we moved skinning to the GPU (vertex skinning in the vertex shader). Each vertex stores:\nan ivec4 of bone indices (maximum 4 bones per vertex), and a vec4 of bone weights (one weight per bone index). On the CPU we upload an array of bone transformation matrices (one mat4 per bone). The vertex shader reads the bone indices and weights, builds a skinning matrix from the corresponding bone matrices, and transforms the vertex position and normal entirely on the GPU.\nI also fixed a bug where some models collapsed toward the origin. The root cause was applying bone transforms relative to the original vertex positions instead of using the mesh origin; the fix was to compute skinned positions relative to the mesh origin and correctly apply bone transformations.\nGPU vertex skinning in action\rBug demonstration: model collapsing to origin before the fix\rSubtitles system\r#\rThe game includes narrative sequences that require subtitles. We used Subtitle Horse to author subtitles and exported them to JSON in order to easily integrate them into our engine.\nI implemented a Subtitles Manager that:\nLoads subtitle timings and text from JSON files Displays timed lines with a typewriter effect Synchronizes subtitles with cutscene timings Subtitles with a typewriter effect\rCutscene end frame with subtitles\rBoss presentation (cinematic camera)\r#\rFor boss introductions I created a cinematic camera system. The camera follows a Bezier curve to focus on the boss for a dramatic reveal. It then smoothly returns to the player before gameplay resumes.\nThis is implemented as a small script that samples a cubic Bezier over normalized time and interpolates both position and orientation.\nCinematic boss introduction using a Bezier camera path\rDummy enemy\r#\rI implemented a dummy enemy used for combat training. The dummy lets players exercise attacks and combos and helps the team debug input timing, hit detection, and animation transitions.\nDummy enemy for combat testing\rDissolve shader\r#\rI implemented a dissolve shader for stylized appearance/disappearance transitions. The effect uses a noise texture (or procedural noise) and a parameter that drives a threshold mask—this creates smooth, controllable fade-ins/fade-outs with edge detail.\n3D models and assets\r#\rI produced characters and game assets, and learned the production art pipeline: sculpting, retopology in Maya, texture painting in Substance, and creating low-poly bases for production.\nGeralt of Rivia\r#\rGeralt concept art\rGeralt retopology process\rGeralt of Rivia in a Chibi Style by Yessica Servin Dominguez on Sketchfab Yennefer of Vengerberg\r#\rYennefer concept and retopology\rYennefer in-engine render\rYennefer The Witcher by Yessica Servin Dominguez on Sketchfab Ghoul enemy\r#\rGhoul concept sculpt\rGhoul size comparison\rGhoul - The Witcher by Yessica Servin Dominguez on Sketchfab Other assets\r#\rI created environmental props such as bushes, rocks and minerals used across scenes.\nHUD design\r#\rI created the HUD layout and icons, iterated on UI prototypes, and implemented polished icons and feedback elements.\nMain menu polish\r#\rFor the main menu I added particle systems and a global bloom post-process to make the scene feel more dynamic and atmospheric.\nLighting tweaks\r#\rI iterated on scene lighting to match each arena\u0026rsquo;s atmosphere, balancing directional lights, ambient contribution and baked elements where appropriate.\nLinks \u0026amp; downloads\r#\rDemo / build: Play on GitHub Pages Source: Github Repository Game Website: Game Website ","date":"12 June 2020","externalUrl":null,"permalink":"/projects/the-witcher-a-bards-tale/","section":"Projects","summary":"","title":"The Witcher: A bard's tale","type":"projects"},{"content":"","date":"29 December 2019","externalUrl":null,"permalink":"/tags/glew/","section":"Tags","summary":"","title":"Glew","type":"tags"},{"content":"\rWhat is Hinata Engine?\r#\rHinata Engine is a game engine developed for the Game Engines subject in the Videogame Design and Development Degree at UPC.\nIt was created collaboratively by Jaume Montagut and myself, with the main goal of understanding how a modern game engine works internally.\nThe engine includes the standard systems you’d expect from a basic editor and runtime:\nModel and texture importing GameObject–Component architecture Scene saving and loading Editor UI based on ImGui Basic camera and rendering pipeline It also features several optimizations such as:\nOctree spatial partitioning Frustum Culling Skeletal Animation, a full research-driven implementation for the final assignment. GitHub Repository My Individual Contributions\r#\rI was responsible for several core engine systems, including:\nFrustum Culling\r#\rImplemented CPU-side visibility checks based on camera frustum planes. Integrated bounding boxes for runtime culling. Added debugging view through the “Configuration → Camera3D” panel. Octree\r#\rImplemented scene spatial partitioning to improve rendering and picking. Added visualization inside the Scene panel. Scene Serialization\r#\rImplemented saving and loading of hierarchical scenes using JSON via Parson. Drag-and-drop scene loading through the editor UI. Mouse Picking\r#\rImplemented ray casting from the camera into the scene. Enabled object selection by clicking on meshes. Skeletal Animation System\r#\rAs part of the research assignment, we implemented a complete skeletal animation system:\nUsed Assimp to import .dae and .fbx files into our custom format. Converted imported data into our own engine format. Implemented bone animation and mesh skinning. Added animation blending between different clips. Enabled visualization of the bone hierarchy for debugging. Supported manual manipulation of bones when the animator component is disabled. Engine Features Overview\r#\rAdding Models\r#\rDrag an .fbx file from the Assets panel into the Scene to automatically create the GameObject hierarchy. Mouse Picking\r#\rClick on any mesh in the Scene view to select it. Frustum Culling (Debug)\r#\rOpen Configuration → Camera3D and enable “See frustum culling”. Move or rotate the camera to visualize the effect. Spatial Partitioning\r#\rThe Octree is always visible in the Scene view for debugging. Time Management\r#\rPlay: run the engine Pause: pause and unpause simulation Resource Management\r#\rResource usage statistics visible in the Resources panel. Scene Serialization\r#\rDrag a scene file into the Scene view to load it. Save scenes via File → Save Scene. Libraries Used\r#\rSDL — windowing and input Dear ImGui — editor UI Glew — OpenGL extension loader Parson — JSON parsing OpenGL 3 — rendering backend ","date":"29 December 2019","externalUrl":null,"permalink":"/projects/hinata-engine/","section":"Projects","summary":"","title":"Hinata Engine","type":"projects"},{"content":"","date":"29 December 2019","externalUrl":null,"permalink":"/tags/imgui/","section":"Tags","summary":"","title":"ImGui","type":"tags"},{"content":"","date":"29 December 2019","externalUrl":null,"permalink":"/tags/parson/","section":"Tags","summary":"","title":"Parson","type":"tags"},{"content":"\rOverview\r#\rSaving The Flamingos is a cooperative game created during the King’s Not Only Games Jam. Two players must work together to guide each other through several levels and rescue flamingos that have been separated from their group.\nPlayers take on the roles of a Mole and a Snake, each with asymmetric abilities:\nThe Mole is blindfolded and cannot see, but can hear all in-game audio cues through headphones. The Snake can see the environment but cannot hear any sound. GitHub Repository How to Play\r#\rBoth players control their character using a gamepad’s D-pad. Alternatively, the keyboard can be used (WASD and IJKL), although it is not recommended for the intended experience.\nMole (blindfolded):\nCannot see the screen. Hears all audio cues. Can detect “Snake traps” through sound. Snake (cannot hear):\nCan see the environment. Cannot hear any audio cues. Can identify “Mole traps” visually. The goal is for both characters to work together and reach the flamingo at the end of each level.\nNot Only Games Jam by King\r#\rThis game was created for the #NotOnlyGamesJam organized by King, under the main theme:\n“Create innovative solutions to increase diversity and inclusion in society.”\nThe subthemes for the jam were “Flamingo” and “Other’s Shoes.”\nWe thank King for inviting us to participate in such an inspiring and inclusive event!\n🏆 Best User Experience Award\r#\rThe game received the Best User Experience Award, recognized for its unique, intuitive, and highly accessible asymmetric mechanics that encouraged collaboration and empathy between players.\nCredits\r#\rAlex Campanar – @IamAcaree David Lozano – @DavidLozano42 Jaume Montagut – @Jaume_Montagut Joan Valiente – @KaikJoan Yessica Servin – @Yessica_SD Spoiler (Gameplay Explanation)\r#\rIf anything is confusing, here is the trap system:\nSnake Traps:\nKill the Snake.\nThe Mole can detect them through sound cues and can walk over them safely.\nMole Traps:\nKill the Mole.\nThe Snake can see them as grey/brown tiles with spikes and can pass over them safely.\n","date":"19 November 2019","externalUrl":null,"permalink":"/projects/savingtheflamingos/","section":"Projects","summary":"","title":"King's Not Only Games Jam - Saving The Flamingos","type":"projects"},{"content":"","date":"26 June 2019","externalUrl":null,"permalink":"/tags/sdl/","section":"Tags","summary":"","title":"SDL","type":"tags"},{"content":"\rOverview\r#\rTankerfield is a 4-player cooperative survival game where players control tanks and fight through waves of enemies. The project was developed by Gamificalo Studio, a team of 8 students from the CITM-UPC University in Terrassa, Spain.\nAs part of the programming team, I implemented several core gameplay and engine systems.\nGitHub Repository\rMy Individual Contribution\r#\rQuadtree integration into the rendering pipeline Controller system (detection, vibration, remapping + persistent save) Enemy AI logic and state-based behavior system Object Pooling System Sprite extraction from original game files \u0026amp; 3D models Improvements to the map module (tile sorting, collider loading) Sprite Extraction\r#\rI researched and implemented the workflow to extract sprites from both:\noriginal game files 3D models (capturing and isolating animation frames) This allowed the team to create higher-quality assets and stay consistent with the original art style.\nMap Module Improvements\r#\rI refactored and extended the map system:\nAdded a Quadtree to the render pipeline\r#\rGreatly improved rendering performance by ensuring tiles and world elements were culled and rendered efficiently.\nTile sorting\r#\rCorrect ordering of elements depending on depth and type.\nAutomatic collider loading from Tiled\r#\rMade level creation faster, less error-prone, and more designer-friendly.\nController System\r#\rImplemented the entire controller pipeline:\nDetection of connected/disconnected controllers Controller vibration Input mapping and remapping UI integration for button prompts Saving user input settings between sessions This system ensured smooth gameplay for all four players and adaptability for different controllers.\nEnemy AI System\r#\rDesigned a state-based AI system, making enemies easier to extend, debug, and balance.\nSome implemented states include:\nGET_PATH – Pathfinding to the nearest player MOVE – Following the generated path BURN – When hit by fire + oil, enemies panic and take damage over time TELEPORT – Enemies far from players reappear closer UNSTUCK – Logic to recover when enemies spawn/move into an unwalkable tile This modular design allowed designers to add new enemy types and abilities quickly.\nObject Pooling System\r#\rDue to the high number of enemies and projectiles on screen, I implemented an object pool to avoid unnecessary memory allocations.\nThis significantly improved performance and memory stability, especially during late waves.\nAdditional Tasks\r#\rImplemented rocket launcher logic (distance-based firing behavior) Multiple bug fixes and stability improvements throughout the project ","date":"26 June 2019","externalUrl":null,"permalink":"/projects/tankerfield/","section":"Projects","summary":"","title":"Tankerfield","type":"projects"},{"content":"","date":"16 December 2018","externalUrl":null,"permalink":"/tags/2d-platformer/","section":"Tags","summary":"","title":"2D Platformer","type":"tags"},{"content":"","date":"16 December 2018","externalUrl":null,"permalink":"/tags/game-development/","section":"Tags","summary":"","title":"Game Development","type":"tags"},{"content":"\rOverview\r#\rSpooky Skeleton is a 2D platformer developed using C++ and SDL. The game features a skeleton protagonist who must traverse two spooky-themed levels: an underground cave and the forested area outside it.\nGitHub Repository\rMy Individual Contribution\r#\rPlayer movement system (including jump logic and custom “sliding on ice” acceleration). Ground enemy behavior. A* Pathfinding implementation for enemies. Map and animation loading using the Tiled (.tmx) format. UI system implementation, fully data-driven and loaded from XML. About the Game\r#\rObjective\nReach the end of each level while avoiding or defeating enemies and collecting all the coins.\nControls\nSPACE – Jump LEFT / RIGHT ARROWS – Move Q – Attack ESC – Open menu Highlights \u0026amp; Features\r#\r❄️ Ice Platform Mechanic\r#\rIce tiles reduce friction, making the player slide. This required adjustments to the acceleration and deceleration logic.\n🧟‍♂️ Enemies \u0026amp; Combat\r#\rThe player can attack zombies and defeat them.\n🧩 Data-Driven UI\r#\rAll UI elements are parsed from XML files, allowing flexible layout changes without modifying the source code.\nCore Subsystems\r#\rThe game is structured around a modular architecture.\nThe main application module (j1App.cpp) manages the lifecycle of all other modules by calling shared base class methods:\nAwake PreUpdate Update PostUpdate CleanUp Entity Factory\r#\rA factory pattern is used to create and manage all in-game entities, improving both organization and performance.\nUI Module\r#\rThe UI system is fully decoupled from gameplay logic.\nIt handles events independently, allowing clean separation between interface and core systems.\nXML-Driven Data\r#\rMaps, animations, textures, file paths, and UI data are loaded from XML.\nThis improves readability, makes iteration easier, and avoids hard-coded “magic numbers.”\n","date":"16 December 2018","externalUrl":null,"permalink":"/projects/spooky-skeleton/","section":"Projects","summary":"","title":"Spooky Skeleton","type":"projects"},{"content":"","date":"16 December 2018","externalUrl":null,"permalink":"/tags/tiled-map-editor/","section":"Tags","summary":"","title":"Tiled Map Editor","type":"tags"},{"content":"\rOverview\r#\rLast Resort is a tribute remake of the 1992 SNK shoot ’em up arcade game.\nThe project was developed from scratch in C++ by a team of four students from the Game Design and Development Degree at UPC–CITM.\nOur goal was to faithfully recreate the core gameplay, enemy behaviors, weapons, and overall feel of the original game while learning how to structure a complete small-scale game engine and gameplay loop.\nGitHub Repository\rMy Individual Contribution\r#\rI contributed to several core gameplay systems, including:\nEnemy Behavior\nImplemented behavior logic for various enemy types, including movement patterns, attack timing, and interactions with the player.\nWeapon Implementation\nDeveloped one of the main weapons and its associated power-up progression, integrating it into the existing combat and collision systems.\nCredits\r#\rManagement \u0026amp; Programming: Jaume Montagut i Guix\nWebsite: wadoren.wixsite.com/gamedev\nGitHub: JaumeMontagut\nArt, QA \u0026amp; Programming: Alejandro Gamarra Niño\nInstagram: @ax3_rt\nGitHub: alejandro61299\nQA: Dani Sanchez Flores\nInstagram: @vampir_nex\nGitHub: Dasanch\nProgramming \u0026amp; Code Review: Yessica Servín Domínguez\nInstagram: @randomgerbit\nGitHub: YessicaSD\nAbout the Game\r#\rSet on the brink of an apocalypse, Last Resort places the player at the controls of a powerful spacecraft accompanied by a support drone known as the “unit.”\nTogether, the goal is to fight through incoming waves of enemies and prevent the approaching catastrophe.\nTribute Game Footage\r#\rOriginal Game Footage\r#\r","date":"3 June 2018","externalUrl":null,"permalink":"/projects/last-resort/","section":"Projects","summary":"","title":"Last Resort","type":"projects"},{"content":"","externalUrl":null,"permalink":"/resume/experience/3dtechomegazeta/","section":"Resume","summary":"","title":"3D Tech Omega Zeta","type":"resume"},{"content":"","externalUrl":null,"permalink":"/authors/","section":"Authors","summary":"","title":"Authors","type":"authors"},{"content":"","externalUrl":null,"permalink":"/categories/","section":"Categories","summary":"","title":"Categories","type":"categories"},{"content":"","externalUrl":null,"permalink":"/resume/education/","section":"Resume","summary":"","title":"Education","type":"resume"},{"content":"This is a test\n","externalUrl":null,"permalink":"/resume/experience/","section":"Resume","summary":"","title":"Experience","type":"resume"},{"content":"","externalUrl":null,"permalink":"/series/","section":"Series","summary":"","title":"Series","type":"series"},{"content":"","externalUrl":null,"permalink":"/resume/experience/unidesa-cirsa/","section":"Resume","summary":"","title":"Unidesa I+D Cirsa","type":"resume"}]