<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Computer Graphics | Étienne Peillard</title><link>https://www.etiennepeillard.com/category/computer-graphics/</link><atom:link href="https://www.etiennepeillard.com/category/computer-graphics/index.xml" rel="self" type="application/rss+xml"/><description>Computer Graphics</description><generator>Wowchemy (https://wowchemy.com)</generator><language>en-us</language><lastBuildDate>Tue, 10 Feb 2026 00:00:00 +0000</lastBuildDate><image><url>https://www.etiennepeillard.com/media/sharing.png</url><title>Computer Graphics</title><link>https://www.etiennepeillard.com/category/computer-graphics/</link></image><item><title>Course — Introduction to 3D rendering</title><link>https://www.etiennepeillard.com/slides/rendering/</link><pubDate>Tue, 10 Feb 2026 00:00:00 +0000</pubDate><guid>https://www.etiennepeillard.com/slides/rendering/</guid><description>&lt;h1 id="introduction-to-3d-rendering">Introduction to 3D Rendering&lt;/h1>
&lt;p>How do we create images of virtual worlds?&lt;/p>
&lt;hr>
&lt;section data-noprocess data-shortcode-slide
class="img-right"
>
&lt;h2 id="what-is-rendering">What is Rendering?&lt;/h2>
&lt;p>Rendering answers a simple question:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>For each pixel on the screen, what color should it be?&lt;/strong>&lt;/p>
&lt;/blockquote>
&lt;ul>
&lt;li>An image = a grid of pixels&lt;/li>
&lt;li>Rendering = computing the color of each pixel&lt;/li>
&lt;li>This depends on:
&lt;ul>
&lt;li>Geometry of the scene&lt;/li>
&lt;li>Materials of objects&lt;/li>
&lt;li>Light sources&lt;/li>
&lt;li>Camera position&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="image and pixel" srcset="
/slides/rendering/image-1_hueb52c679ed301417390574538c115424_759451_e2202c497e5d9c329c5df5056c26ab1d.webp 400w,
/slides/rendering/image-1_hueb52c679ed301417390574538c115424_759451_7416d1e57497d6fd9b34e4bd9930fd46.webp 760w,
/slides/rendering/image-1_hueb52c679ed301417390574538c115424_759451_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.etiennepeillard.com/slides/rendering/image-1_hueb52c679ed301417390574538c115424_759451_e2202c497e5d9c329c5df5056c26ab1d.webp"
width="760"
height="507"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;hr>
&lt;h2 id="two-ways-to-think-about-rendering">Two ways to think about rendering&lt;/h2>
&lt;h3 id="1-image-first-modern-view">1) Image-first (modern view)&lt;/h3>
&lt;p>For each pixel:&lt;/p>
&lt;ul>
&lt;li>What light reaches the camera?&lt;/li>
&lt;li>How does the surface reflect it?&lt;/li>
&lt;li>How do we approximate this efficiently?&lt;/li>
&lt;/ul>
&lt;h3 id="2-geometry-first-historical-view">2) Geometry-first (historical view)&lt;/h3>
&lt;p>Transform 3D objects → project → shade → display.&lt;/p>
&lt;p>In this course, we start from the &lt;strong>image-first view&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h1 id="part-i--cameras-and-projection">Part I — Cameras and Projection&lt;/h1>
&lt;hr>
&lt;section data-noprocess data-shortcode-slide
class="img-right"
>
&lt;h2 id="virtual-camera">Virtual Camera&lt;/h2>
&lt;p>A virtual camera is defined by:&lt;/p>
&lt;ul>
&lt;li>Position (&lt;code>isAt&lt;/code>)&lt;/li>
&lt;li>Viewing direction (&lt;code>lookAt&lt;/code>)&lt;/li>
&lt;li>Up vector&lt;/li>
&lt;li>Field of view (FOV)&lt;/li>
&lt;/ul>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="camera and projection plane" srcset="
/slides/rendering/image_hu1c74b158a57610c13a0399e1bd559036_210382_76e2ddd7696d449b44b254670882d3af.webp 400w,
/slides/rendering/image_hu1c74b158a57610c13a0399e1bd559036_210382_0b9782f0d61ad3b6ce1ff0fcae57e7d8.webp 760w,
/slides/rendering/image_hu1c74b158a57610c13a0399e1bd559036_210382_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.etiennepeillard.com/slides/rendering/image_hu1c74b158a57610c13a0399e1bd559036_210382_76e2ddd7696d449b44b254670882d3af.webp"
width="760"
height="527"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;hr>
&lt;section data-noprocess data-shortcode-slide
class="img-right"
>
&lt;h2 id="projection-3d--2d">Projection: 3D → 2D&lt;/h2>
&lt;p>We must map 3D points to 2D pixels.&lt;/p>
&lt;p>Two main types of projection:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Parallel (orthographic) projection&lt;/strong>
&lt;ul>
&lt;li>No size change with distance&lt;/li>
&lt;li>Useful for technical drawings, CAD, UI&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="parallel projection" srcset="
/slides/rendering/image-2_hu098f372a051fcb1ba31f0415c306411b_282688_3250ab0032720a14f0985cdea70a3be2.webp 400w,
/slides/rendering/image-2_hu098f372a051fcb1ba31f0415c306411b_282688_8e2bcd5854f92ef4b92a994f874b42aa.webp 760w,
/slides/rendering/image-2_hu098f372a051fcb1ba31f0415c306411b_282688_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.etiennepeillard.com/slides/rendering/image-2_hu098f372a051fcb1ba31f0415c306411b_282688_3250ab0032720a14f0985cdea70a3be2.webp"
width="760"
height="495"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;hr>
&lt;section data-noprocess data-shortcode-slide
class="img-right"
>
&lt;ul>
&lt;li>&lt;strong>Perspective projection&lt;/strong>
&lt;ul>
&lt;li>Distant objects appear smaller&lt;/li>
&lt;li>Matches human vision and photography&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="perspective projection" srcset="
/slides/rendering/image-3_hud5011720c51376eb8b4f51a07b8e92e5_266157_77b9a746432ab186d6e537feae41f2ed.webp 400w,
/slides/rendering/image-3_hud5011720c51376eb8b4f51a07b8e92e5_266157_27d71c412bc026008bcdefeca9de8678.webp 760w,
/slides/rendering/image-3_hud5011720c51376eb8b4f51a07b8e92e5_266157_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.etiennepeillard.com/slides/rendering/image-3_hud5011720c51376eb8b4f51a07b8e92e5_266157_77b9a746432ab186d6e537feae41f2ed.webp"
width="760"
height="499"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;hr>
&lt;section data-noprocess data-shortcode-slide
class="img-right"
>
&lt;h2 id="perspective-and-field-of-view">Perspective and Field of View&lt;/h2>
&lt;p>Key parameters:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Focal length&lt;/strong> (camera metaphor)&lt;/li>
&lt;li>&lt;strong>Field of View (FOV)&lt;/strong>:
&lt;ul>
&lt;li>Horizontal FOV&lt;/li>
&lt;li>Vertical FOV&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>Smaller focal length → wider FOV&lt;br>
Larger focal length → narrower FOV&lt;/p>
&lt;div class="img-stack">
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="alt text" srcset="
/slides/rendering/image-4_hu1236b913a2688cd87c4b39aef455c842_33302_ad83881a2ba3864acd8ea4e8afb6cbaf.webp 400w,
/slides/rendering/image-4_hu1236b913a2688cd87c4b39aef455c842_33302_61b9ee8deb53c567b1b047206160b7d2.webp 760w,
/slides/rendering/image-4_hu1236b913a2688cd87c4b39aef455c842_33302_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.etiennepeillard.com/slides/rendering/image-4_hu1236b913a2688cd87c4b39aef455c842_33302_ad83881a2ba3864acd8ea4e8afb6cbaf.webp"
width="760"
height="368"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="alt text" srcset="
/slides/rendering/image-5_hu0d5d860b8b29691f737ac9427057efc0_45790_1d8e9eae30cec580bfea019b5d4530b8.webp 400w,
/slides/rendering/image-5_hu0d5d860b8b29691f737ac9427057efc0_45790_2ea2c63a242038d8441530025c3b6c77.webp 760w,
/slides/rendering/image-5_hu0d5d860b8b29691f737ac9427057efc0_45790_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.etiennepeillard.com/slides/rendering/image-5_hu0d5d860b8b29691f737ac9427057efc0_45790_1d8e9eae30cec580bfea019b5d4530b8.webp"
width="760"
height="353"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;/div>
&lt;hr>
&lt;section data-noprocess data-shortcode-slide
class="img-right"
>
&lt;h2 id="the-view-frustum-view-pyramid">The View Frustum (View Pyramid)&lt;/h2>
&lt;p>The camera sees only what lies inside a 3D volume:&lt;/p>
&lt;ul>
&lt;li>Near plane&lt;/li>
&lt;li>Far plane&lt;/li>
&lt;li>Left, right, top, bottom planes&lt;/li>
&lt;/ul>
&lt;p>This defines what can potentially appear on screen.&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="alt text" srcset="
/slides/rendering/image-6_huf707be182f6bb46f7cac4f128c6e1929_49677_fd342a04b5a4d865cea14cf22f0e1d8f.webp 400w,
/slides/rendering/image-6_huf707be182f6bb46f7cac4f128c6e1929_49677_47bcc243fae36cc4bcbc5c13b259b0fc.webp 760w,
/slides/rendering/image-6_huf707be182f6bb46f7cac4f128c6e1929_49677_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.etiennepeillard.com/slides/rendering/image-6_huf707be182f6bb46f7cac4f128c6e1929_49677_fd342a04b5a4d865cea14cf22f0e1d8f.webp"
width="760"
height="475"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;hr>
&lt;section data-noprocess data-shortcode-slide
class="img-right"
>
&lt;h2 id="head-tracking-and-dynamic-frustum">Head Tracking and Dynamic Frustum&lt;/h2>
&lt;p>In VR / AR:&lt;/p>
&lt;ul>
&lt;li>The frustum &lt;strong>deforms with head position&lt;/strong>&lt;/li>
&lt;li>It is defined by:
&lt;ul>
&lt;li>The four screen corners&lt;/li>
&lt;li>The viewer’s eye position&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>This enables correct perspective for each eye.&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="alt text" srcset="
/slides/rendering/image-7_hu068ae31cff14bda7b5c8bfa13d68fe42_60768_87ccf5b55ce5e9589362503628fa24df.webp 400w,
/slides/rendering/image-7_hu068ae31cff14bda7b5c8bfa13d68fe42_60768_544965e44ad212e5a0ecd535d6c69712.webp 760w,
/slides/rendering/image-7_hu068ae31cff14bda7b5c8bfa13d68fe42_60768_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.etiennepeillard.com/slides/rendering/image-7_hu068ae31cff14bda7b5c8bfa13d68fe42_60768_87ccf5b55ce5e9589362503628fa24df.webp"
width="677"
height="463"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;hr>
&lt;h1 id="part-ii--from-3d-to-pixels-rasterization-modern-gpu-view">Part II — From 3D to Pixels: Rasterization (Modern GPU View)&lt;/h1>
&lt;hr>
&lt;h2 id="two-families-of-rendering">Two Families of Rendering&lt;/h2>
&lt;h3 id="rasterization-real-time-gpus">Rasterization (real-time, GPUs)&lt;/h3>
&lt;ul>
&lt;li>Used in games, VR, AR&lt;/li>
&lt;li>Very fast&lt;/li>
&lt;li>Approximates light behavior&lt;/li>
&lt;/ul>
&lt;h3 id="ray-tracing--path-tracing-physically-based">Ray Tracing / Path Tracing (physically based)&lt;/h3>
&lt;ul>
&lt;li>Traces rays of light through the scene&lt;/li>
&lt;li>More realistic reflections, shadows, global illumination&lt;/li>
&lt;li>Historically slow → now accelerated with modern GPUs&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="the-modern-graphics-pipeline-simplified">The Modern Graphics Pipeline (Simplified)&lt;/h2>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="alt text" srcset="
/slides/rendering/image-8_hub634f7d2d18ea0ff0c71934c5858ce5a_465511_510084bbaa878f80c3378b1f2bd007de.webp 400w,
/slides/rendering/image-8_hub634f7d2d18ea0ff0c71934c5858ce5a_465511_458444de0d44d4fd1494c884a3fd38d0.webp 760w,
/slides/rendering/image-8_hub634f7d2d18ea0ff0c71934c5858ce5a_465511_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.etiennepeillard.com/slides/rendering/image-8_hub634f7d2d18ea0ff0c71934c5858ce5a_465511_510084bbaa878f80c3378b1f2bd007de.webp"
width="760"
height="392"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;hr>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Vertex Processing&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Transform 3D vertices to screen space&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Rasterization&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Convert triangles into pixels (fragments)&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Fragment (Pixel) Shading&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Compute color using materials and lights&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Post-processing&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Tone mapping, bloom, color grading&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;section data-noprocess data-shortcode-slide
class="img-right"
>
&lt;h2 id="visibility-what-do-we-actually-see">Visibility: What do we actually see?&lt;/h2>
&lt;p>Before shading, the GPU determines visibility:&lt;/p>
&lt;p>&lt;strong>Back-face Culling&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Triangles facing away from the camera are discarded&lt;/li>
&lt;li>Saves computation&lt;/li>
&lt;/ul>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="alt text" srcset="
/slides/rendering/image-9_hu3ef0466a90cb44dfbd0fde46e8228b77_66497_62ed816b86d1d0699cd72547f665f309.webp 400w,
/slides/rendering/image-9_hu3ef0466a90cb44dfbd0fde46e8228b77_66497_ff240ebed3cb7e9fa956b56804d46ffd.webp 760w,
/slides/rendering/image-9_hu3ef0466a90cb44dfbd0fde46e8228b77_66497_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.etiennepeillard.com/slides/rendering/image-9_hu3ef0466a90cb44dfbd0fde46e8228b77_66497_62ed816b86d1d0699cd72547f665f309.webp"
width="760"
height="402"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;hr>
&lt;section data-noprocess data-shortcode-slide
class="img-right"
>
&lt;h2 id="depth-buffer-z-buffer--in-practice">Depth Buffer (Z-Buffer) — in practice&lt;/h2>
&lt;p>For each pixel, we store the depth of the closest surface.&lt;/p>
&lt;p>If a new fragment is farther away → it is discarded.&lt;/p>
&lt;p>This solves hidden surface removal efficiently.&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="alt text" srcset="
/slides/rendering/image-10_hu799b3dff0b97e0199b10c1d636c46d7a_724041_033f6bc64dadfb916fae7751a5ce84ab.webp 400w,
/slides/rendering/image-10_hu799b3dff0b97e0199b10c1d636c46d7a_724041_77bfd941cc528ab85981a40a5fcd0aab.webp 760w,
/slides/rendering/image-10_hu799b3dff0b97e0199b10c1d636c46d7a_724041_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.etiennepeillard.com/slides/rendering/image-10_hu799b3dff0b97e0199b10c1d636c46d7a_724041_033f6bc64dadfb916fae7751a5ce84ab.webp"
width="760"
height="509"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;hr>
&lt;h2 id="practical-issues-with-depth">Practical issues with depth&lt;/h2>
&lt;p>Common problems in real engines:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Z-fighting&lt;/strong>: precision issues when surfaces are very close&lt;/li>
&lt;li>&lt;strong>Overdraw&lt;/strong>: many fragments drawn but not visible&lt;/li>
&lt;li>&lt;strong>Transparency sorting&lt;/strong>: complex with alpha blending&lt;/li>
&lt;/ul>
&lt;p>(These are key modern graphics concerns.)&lt;/p>
&lt;hr>
&lt;h1 id="part-iii--materials-and-lighting-modern-approach">Part III — Materials and Lighting (Modern Approach)&lt;/h1>
&lt;hr>
&lt;section data-noprocess data-shortcode-slide
class="img-right"
>
&lt;h2 id="how-light-creates-color">How light creates color&lt;/h2>
&lt;p>At each point on a surface, light interacts with the material:&lt;/p>
&lt;p>Three intuitive components (historical model):&lt;/p>
&lt;ul>
&lt;li>Ambient&lt;/li>
&lt;li>Diffuse&lt;/li>
&lt;li>Specular&lt;/li>
&lt;/ul>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="alt text" srcset="
/slides/rendering/image-11_hu40f1077378f0bee4c1955c16b1545f19_243109_f46992323966029b4d0438138ec0b308.webp 400w,
/slides/rendering/image-11_hu40f1077378f0bee4c1955c16b1545f19_243109_4a9bcc3633877604966ab1116afd8bff.webp 760w,
/slides/rendering/image-11_hu40f1077378f0bee4c1955c16b1545f19_243109_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.etiennepeillard.com/slides/rendering/image-11_hu40f1077378f0bee4c1955c16b1545f19_243109_f46992323966029b4d0438138ec0b308.webp"
width="460"
height="449"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;hr>
&lt;h3 id="ambient-lighting">Ambient lighting&lt;/h3>
&lt;p>Each object is shown with an intrinsic intensity:&lt;/p>
&lt;ul>
&lt;li>No external source&lt;/li>
&lt;li>Unreal universe of non-reflective light objects&lt;/li>
&lt;/ul>
&lt;hr>
&lt;section data-noprocess data-shortcode-slide
class="img-right"
>
&lt;h3 id="diffuse-lighting">Diffuse lighting&lt;/h3>
&lt;p>Part of the incident light enters the object and exits with the same intensity in all directions&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="alt text" srcset="
/slides/rendering/image-12_hu135983857d1de0283dedd269c38836df_80075_180bb2d3ec596918d854884082d83c02.webp 400w,
/slides/rendering/image-12_hu135983857d1de0283dedd269c38836df_80075_7bc4712f7aa4edbf4ae84dee571b162d.webp 760w,
/slides/rendering/image-12_hu135983857d1de0283dedd269c38836df_80075_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.etiennepeillard.com/slides/rendering/image-12_hu135983857d1de0283dedd269c38836df_80075_180bb2d3ec596918d854884082d83c02.webp"
width="760"
height="379"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;hr>
&lt;section data-noprocess data-shortcode-slide
class="img-right"
>
&lt;h3 id="specular-lighting">Specular lighting&lt;/h3>
&lt;p>Reflection from the surface of the object of incident light that has not penetrated the object, depending on the direction of observation&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="alt text" srcset="
/slides/rendering/image-13_huef6319e428fb331bc511dcf891def847_83177_8961f857c150c82b684b58212c99eb15.webp 400w,
/slides/rendering/image-13_huef6319e428fb331bc511dcf891def847_83177_3479fc4abd8d46d2c0e8a9d4a8b4d9d8.webp 760w,
/slides/rendering/image-13_huef6319e428fb331bc511dcf891def847_83177_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.etiennepeillard.com/slides/rendering/image-13_huef6319e428fb331bc511dcf891def847_83177_8961f857c150c82b684b58212c99eb15.webp"
width="760"
height="363"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;hr>
&lt;h2 id="from-phong-to-pbr-modern-materials">From Phong to PBR (Modern Materials)&lt;/h2>
&lt;p>Modern engines use &lt;strong>Physically Based Rendering (PBR)&lt;/strong> instead of classic Phong.&lt;/p>
&lt;p>A PBR material is typically defined by:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Albedo&lt;/strong> (base color)&lt;/li>
&lt;li>&lt;strong>Roughness&lt;/strong> (matte vs shiny)&lt;/li>
&lt;li>&lt;strong>Metallic&lt;/strong> (metal vs non-metal)&lt;/li>
&lt;li>&lt;strong>Normal map&lt;/strong> (fake surface detail)&lt;/li>
&lt;/ul>
&lt;p>This ensures:&lt;/p>
&lt;ul>
&lt;li>Realistic lighting&lt;/li>
&lt;li>Consistency across different light conditions&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="why-pbr-is-better">Why PBR is better&lt;/h2>
&lt;p>With Phong:&lt;/p>
&lt;ul>
&lt;li>Energy is not conserved (objects can appear “too bright”)&lt;/li>
&lt;/ul>
&lt;p>With PBR:&lt;/p>
&lt;ul>
&lt;li>Energy is conserved&lt;/li>
&lt;li>Materials look correct under any lighting&lt;/li>
&lt;/ul>
&lt;hr>
&lt;section data-noprocess data-shortcode-slide
class="img-right"
>
&lt;h2 id="surface-smoothing">Surface Smoothing&lt;/h2>
&lt;p>To avoid “faceted” appearance:&lt;/p>
&lt;p>&lt;strong>Gouraud shading&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Interpolate colors across triangles&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Phong shading&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Interpolate normals, compute lighting per pixel&lt;/li>
&lt;/ul>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="alt text" srcset="
/slides/rendering/image-14_hu55f5637cf24ceaf1dd22ae6d8204feb6_204826_88a9521556b15340d1d436524a9087b5.webp 400w,
/slides/rendering/image-14_hu55f5637cf24ceaf1dd22ae6d8204feb6_204826_ec75d482a3e53efe09e730cb4878c5c7.webp 760w,
/slides/rendering/image-14_hu55f5637cf24ceaf1dd22ae6d8204feb6_204826_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.etiennepeillard.com/slides/rendering/image-14_hu55f5637cf24ceaf1dd22ae6d8204feb6_204826_88a9521556b15340d1d436524a9087b5.webp"
width="760"
height="275"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;hr>
&lt;h2 id="what-is-a-material">What is a Material?&lt;/h2>
&lt;p>In practice, a material includes:&lt;/p>
&lt;ul>
&lt;li>Base color&lt;/li>
&lt;li>Roughness&lt;/li>
&lt;li>Metallic&lt;/li>
&lt;li>Normal map&lt;/li>
&lt;li>Transparency (alpha)&lt;/li>
&lt;li>Emissive color (self-illumination)&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h1 id="part-iv--textures-essential-for-realism">Part IV — Textures (Essential for Realism)&lt;/h1>
&lt;hr>
&lt;section data-noprocess data-shortcode-slide
class="img-right"
>
&lt;h2 id="what-is-a-texture">What is a Texture?&lt;/h2>
&lt;p>A texture is a 2D image mapped onto a 3D surface.&lt;/p>
&lt;p>Each vertex gets UV coordinates (u, v) in [0,1].&lt;/p>
&lt;p>For each pixel, texture color is interpolated.&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="alt text" srcset="
/slides/rendering/image-15_hu851b4d0668cb3f9280b2297012a6065e_99711_165fbbafd9ec9ab073214f979268cf1b.webp 400w,
/slides/rendering/image-15_hu851b4d0668cb3f9280b2297012a6065e_99711_c0cbd304b74a038d17bbe96a4a617bed.webp 760w,
/slides/rendering/image-15_hu851b4d0668cb3f9280b2297012a6065e_99711_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.etiennepeillard.com/slides/rendering/image-15_hu851b4d0668cb3f9280b2297012a6065e_99711_165fbbafd9ec9ab073214f979268cf1b.webp"
width="760"
height="346"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;hr>
&lt;h2 id="beyond-color-modern-texture-maps">Beyond Color: Modern Texture Maps&lt;/h2>
&lt;p>Today, textures are used for much more than color:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Normal maps&lt;/strong> → fake fine detail&lt;/li>
&lt;li>&lt;strong>Roughness maps&lt;/strong> → control shininess&lt;/li>
&lt;li>&lt;strong>Metallic maps&lt;/strong> → define metal areas&lt;/li>
&lt;li>&lt;strong>Ambient occlusion maps&lt;/strong> → fake soft shadows&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h1 id="part-v--modern-rendering-techniques">Part V — Modern Rendering Techniques&lt;/h1>
&lt;hr>
&lt;h2 id="shadows">Shadows&lt;/h2>
&lt;p>Most real-time engines use &lt;strong>shadow maps&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>Render the scene from the light’s point of view&lt;/li>
&lt;li>Store depth information&lt;/li>
&lt;li>Use it to determine shadowed areas&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="global-illumination">Global Illumination&lt;/h2>
&lt;p>Two main approaches:&lt;/p>
&lt;h3 id="baked-gi-offline">Baked GI (offline)&lt;/h3>
&lt;ul>
&lt;li>Precomputed lighting&lt;/li>
&lt;li>Very stable, cheap at runtime&lt;/li>
&lt;/ul>
&lt;h3 id="real-time-gi">Real-time GI&lt;/h3>
&lt;ul>
&lt;li>Dynamic lighting updates&lt;/li>
&lt;li>Used in modern engines (Unreal Lumen, Unity HDRP)&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="screen-space-effects">Screen-Space Effects&lt;/h2>
&lt;p>Computed directly from the final image:&lt;/p>
&lt;ul>
&lt;li>SSAO (soft ambient shadows)&lt;/li>
&lt;li>Screen-space reflections&lt;/li>
&lt;li>Motion blur&lt;/li>
&lt;li>Bloom&lt;/li>
&lt;li>Tone mapping&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="stereoscopic-rendering-vr">Stereoscopic Rendering (VR)&lt;/h2>
&lt;p>For VR, we render:&lt;/p>
&lt;ul>
&lt;li>One image per eye&lt;/li>
&lt;li>Two slightly different cameras&lt;/li>
&lt;li>Two frustums&lt;/li>
&lt;li>Two rasterization passes&lt;/li>
&lt;/ul>
&lt;p>Smart engines share work between both eyes when possible.&lt;/p>
&lt;hr>
&lt;h1 id="conclusion">Conclusion&lt;/h1>
&lt;p>Modern rendering combines:&lt;/p>
&lt;ul>
&lt;li>Fast rasterization for real-time&lt;/li>
&lt;li>Physically based materials (PBR)&lt;/li>
&lt;li>Smart approximations (shadow maps, GI, screen-space effects)&lt;/li>
&lt;li>Increasing use of ray tracing for realism&lt;/li>
&lt;/ul></description></item><item><title>Lab — 3D rendering: stylized diorama</title><link>https://www.etiennepeillard.com/teaching/lab/tp-rendering/</link><pubDate>Tue, 10 Feb 2026 00:00:00 +0000</pubDate><guid>https://www.etiennepeillard.com/teaching/lab/tp-rendering/</guid><description>&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="alt text" srcset="
/teaching/lab/tp-rendering/image_hu7dd5aef356258fbf43cea35437bc6427_896510_f08c89c3dbed374e7e7f06c6bec96ad9.webp 400w,
/teaching/lab/tp-rendering/image_hu7dd5aef356258fbf43cea35437bc6427_896510_db6fd58d848071eb6f19061ff6d231f5.webp 760w,
/teaching/lab/tp-rendering/image_hu7dd5aef356258fbf43cea35437bc6427_896510_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.etiennepeillard.com/teaching/lab/tp-rendering/image_hu7dd5aef356258fbf43cea35437bc6427_896510_f08c89c3dbed374e7e7f06c6bec96ad9.webp"
width="760"
height="189"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;h2 id="-tp-objective">🎯 TP Objective&lt;/h2>
&lt;p>Create a &lt;strong>diorama-style scene&lt;/strong> (a small miniature world) in &lt;strong>Unity using URP&lt;/strong>, working on:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>visual composition&lt;/strong> (staging, readability, focal point),&lt;/li>
&lt;li>&lt;strong>rendering&lt;/strong> (lighting, materials, post-processing),&lt;/li>
&lt;li>and an initial &lt;strong>tech-art dimension&lt;/strong> (Shader Graph and/or VFX).&lt;/li>
&lt;/ul>
&lt;p>The final result must be &lt;strong>visually coherent&lt;/strong>: even if you use external assets, you must harmonize their materials and the lighting atmosphere.&lt;/p>
&lt;hr>
&lt;h2 id="-mandatory-requirements-common-core">📌 Mandatory requirements (common core)&lt;/h2>
&lt;p>Your scene &lt;strong>must include&lt;/strong> the following elements:&lt;/p>
&lt;h3 id="1-composition--environment">1) Composition / environment&lt;/h3>
&lt;ul>
&lt;li>A readable diorama-style scene (miniature scale, clear framing, focal point).&lt;/li>
&lt;li>You may use free assets (Asset Store, Kenney, Poly Pizza, etc.),&lt;br>
&lt;strong>but you must modify their materials to ensure visual coherence&lt;/strong>.&lt;/li>
&lt;/ul>
&lt;h3 id="2-lighting">2) Lighting&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>At least 3 distinct light sources&lt;/strong>, for example:
&lt;ul>
&lt;li>Directional Light (sun),&lt;/li>
&lt;li>Spot Light (to highlight an object),&lt;/li>
&lt;li>Point Light (local ambiance).&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Expectation: clear intent (warm/cold atmosphere, contrasts, visual hierarchy).&lt;/li>
&lt;/ul>
&lt;h3 id="3-skybox--environment">3) Skybox / environment&lt;/h3>
&lt;ul>
&lt;li>A &lt;strong>Skybox&lt;/strong> (HDRI or procedural).&lt;/li>
&lt;li>Environment settings (Ambient Light, Reflections).&lt;/li>
&lt;/ul>
&lt;h3 id="4-visual-effects">4) Visual effects&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>At least 1 Particle System (Shuriken)&lt;/strong> integrated into the scene&lt;br>
(smoke, dust, snow, fireflies, sparks, bubbles…).&lt;/li>
&lt;li>&lt;strong>At least 1 URP post-processing Volume&lt;/strong>, including at minimum:
&lt;ul>
&lt;li>Bloom &lt;strong>or&lt;/strong>&lt;/li>
&lt;li>Color Adjustments.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="5-materials-and-shaders">5) Materials and shaders&lt;/h3>
&lt;ul>
&lt;li>Use &lt;strong>at least one standard URP Material (Lit)&lt;/strong>.&lt;/li>
&lt;li>Create &lt;strong>at least one custom Shader with Shader Graph&lt;/strong>, and apply it to an object in the scene.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="-optional-features">🧩 Optional features&lt;/h2>
&lt;p>These options allow you to go further depending on your level and creativity.&lt;/p>
&lt;h3 id="a--advanced-lighting-recommended">A — Advanced Lighting (recommended)&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Baked or Mixed&lt;/strong> lighting.&lt;/li>
&lt;li>Use of &lt;strong>Light Probes&lt;/strong> and/or &lt;strong>Reflection Probes&lt;/strong> to improve rendering.&lt;/li>
&lt;/ul>
&lt;h3 id="b--vfx-graph-or-advanced-particles">B — VFX Graph (or advanced particles)&lt;/h3>
&lt;ul>
&lt;li>An effect using &lt;strong>VFX Graph&lt;/strong> (if compatible with your Unity version),&lt;br>
&lt;strong>or&lt;/strong> an advanced Particle System (collision, noise, trails, forces).&lt;/li>
&lt;/ul>
&lt;h3 id="c--cinematic-timeline">C — Cinematic (Timeline)&lt;/h3>
&lt;ul>
&lt;li>A short cinematic of &lt;strong>5 to 10 seconds&lt;/strong> including:
&lt;ul>
&lt;li>camera movement,&lt;/li>
&lt;li>reveal of the focal point,&lt;/li>
&lt;li>variation in lighting or effects.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="d--in-editor-modeling-probuilder">D — In-editor modeling (ProBuilder)&lt;/h3>
&lt;ul>
&lt;li>Create &lt;strong>at least two decorative elements&lt;/strong> with ProBuilder&lt;br>
(base, stylized rock, arch, wall, bridge, platform…).&lt;/li>
&lt;/ul>
&lt;h3 id="e--simple-interaction">E — Simple interaction&lt;/h3>
&lt;p>Implement &lt;strong>one basic interaction&lt;/strong>, for example:&lt;/p>
&lt;ul>
&lt;li>day/night toggle,&lt;/li>
&lt;li>color palette switch,&lt;/li>
&lt;li>enable/disable particles,&lt;/li>
&lt;li>opening a door,&lt;/li>
&lt;li>turning on a lantern.&lt;/li>
&lt;/ul>
&lt;h3 id="f--sound-atmosphere">F — Sound atmosphere&lt;/h3>
&lt;p>Add:&lt;/p>
&lt;ul>
&lt;li>an ambient soundscape (wind, forest, sea, factory, city…),&lt;/li>
&lt;li>at least one 3D spatialized sound effect.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="-theme-ideas-optional">🎨 Theme ideas (optional)&lt;/h2>
&lt;p>To avoid too many similar scenes, you can draw inspiration from these ideas:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Miniature workshop&lt;/strong> (watchmaker, alchemist, tinkerer).&lt;/li>
&lt;li>&lt;strong>Ruins in a bubble&lt;/strong> (temple, statues, vegetation).&lt;/li>
&lt;li>&lt;strong>Miniature subway station&lt;/strong> (neon lights, smoke, reflections).&lt;/li>
&lt;li>&lt;strong>Snowy cabin&lt;/strong> (snow + warm interior lighting).&lt;/li>
&lt;li>&lt;strong>Stylized underwater scene&lt;/strong> (bubbles, simulated caustics, particles).&lt;/li>
&lt;/ul>
&lt;p>You may also propose your own theme, as long as it follows the &lt;em>diorama&lt;/em> spirit.&lt;/p>
&lt;hr>
&lt;h2 id="-expected-deliverables">📦 Expected deliverables&lt;/h2>
&lt;h3 id="1-unity-project">1) Unity Project&lt;/h3>
&lt;ul>
&lt;li>Main scene named: &lt;code>Diorama.unity&lt;/code>&lt;/li>
&lt;li>Functional project in &lt;strong>URP&lt;/strong>.&lt;/li>
&lt;/ul>
&lt;h3 id="2-readme-1-page-max">2) README (1 page max)&lt;/h3>
&lt;p>To include in the project (Markdown or PDF):&lt;/p>
&lt;ul>
&lt;li>Title and theme of the diorama,&lt;/li>
&lt;li>Checklist of the 5 mandatory requirements,&lt;/li>
&lt;li>List of the 2 chosen options (with short justification),&lt;/li>
&lt;li>Sources of used assets (links + licenses).&lt;/li>
&lt;/ul>
&lt;h3 id="3-presentation-image-or-video">3) Presentation image or video&lt;/h3>
&lt;ul>
&lt;li>one fixed “beauty shot”,&lt;/li>
&lt;li>one short camera movement (pan, rotation, or tracking shot).&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="-indicative-grading-scheme">🧮 Indicative grading scheme&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Criterion&lt;/th>
&lt;th>Weight&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Composition &amp;amp; artistic direction&lt;/td>
&lt;td>&lt;strong>30 %&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Material coherence&lt;/td>
&lt;td>&lt;strong>25 %&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Lighting, Skybox &amp;amp; Post-process&lt;/td>
&lt;td>&lt;strong>20 %&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Shader Graph (quality + integration)&lt;/td>
&lt;td>&lt;strong>15 %&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Chosen options (relevance)&lt;/td>
&lt;td>&lt;strong>10 %&lt;/strong>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>Bonus&lt;/strong>: overall polish (small animations, details, simple optimization).&lt;/p>
&lt;hr>
&lt;h2 id="-useful-resources">📚 Useful resources&lt;/h2>
&lt;h3 id="free-assets">Free assets&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>3d textures&lt;/strong>: &lt;a href="https://3dtextures.me" target="_blank" rel="noopener">https://3dtextures.me&lt;/a>&lt;/li>
&lt;li>&lt;strong>Kenney (CC0)&lt;/strong>: &lt;a href="https://kenney.nl" target="_blank" rel="noopener">https://kenney.nl&lt;/a>&lt;/li>
&lt;li>&lt;strong>Poly Pizza&lt;/strong>: &lt;a href="https://poly.pizza" target="_blank" rel="noopener">https://poly.pizza&lt;/a>&lt;/li>
&lt;li>&lt;strong>Poly Haven (HDRI Skyboxes)&lt;/strong>: &lt;a href="https://polyhaven.com" target="_blank" rel="noopener">https://polyhaven.com&lt;/a>&lt;/li>
&lt;li>&lt;strong>Unity Asset Store (Top Free)&lt;/strong>: &lt;a href="https://assetstore.unity.com/top-assets/top-free" target="_blank" rel="noopener">https://assetstore.unity.com/top-assets/top-free&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="shader-graph">Shader Graph&lt;/h3>
&lt;ul>
&lt;li>Unity Learn – Getting started:&lt;br>
&lt;a href="https://learn.unity.com/tutorial/get-started-with-shader-graph" target="_blank" rel="noopener">https://learn.unity.com/tutorial/get-started-with-shader-graph&lt;/a>&lt;/li>
&lt;li>Shader examples:&lt;br>
&lt;a href="https://www.youtube.com/playlist?list=PLsaDw3p1XpJiPp3v5gUyxuWkmUn3eB731" target="_blank" rel="noopener">https://www.youtube.com/playlist?list=PLsaDw3p1XpJiPp3v5gUyxuWkmUn3eB731&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="urp-post-processing">URP Post-processing&lt;/h3>
&lt;ul>
&lt;li>Official documentation:&lt;br>
&lt;a href="https://docs.unity3d.com/Manual/urp-integration-with-post-processing.html" target="_blank" rel="noopener">https://docs.unity3d.com/Manual/urp-integration-with-post-processing.html&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="particles--vfx">Particles / VFX&lt;/h3>
&lt;ul>
&lt;li>VFX Graph (Unity 6):&lt;br>
&lt;a href="https://unity.com/resources/creating-advanced-vfx-unity6" target="_blank" rel="noopener">https://unity.com/resources/creating-advanced-vfx-unity6&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="lighting-baked-probes">Lighting (Baked, Probes)&lt;/h3>
&lt;ul>
&lt;li>Reflection Probes:&lt;br>
&lt;a href="https://docs.unity3d.com/Manual/class-ReflectionProbe.html" target="_blank" rel="noopener">https://docs.unity3d.com/Manual/class-ReflectionProbe.html&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="probuilder">ProBuilder&lt;/h3>
&lt;ul>
&lt;li>Documentation:&lt;br>
&lt;a href="https://docs.unity3d.com/Packages/com.unity.probuilder" target="_blank" rel="noopener">https://docs.unity3d.com/Packages/com.unity.probuilder&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="timeline--cinematic">Timeline / Cinematic&lt;/h3>
&lt;ul>
&lt;li>Official introduction:&lt;br>
&lt;a href="https://unity.com/blog/games/first-guide-animation-in-unity" target="_blank" rel="noopener">https://unity.com/blog/games/first-guide-animation-in-unity&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Lab — Unity 3D basics</title><link>https://www.etiennepeillard.com/teaching/lab/intro-unity/</link><pubDate>Mon, 02 Feb 2026 00:00:00 +0000</pubDate><guid>https://www.etiennepeillard.com/teaching/lab/intro-unity/</guid><description>&lt;section class="unity-intro" aria-label="Lab overview">
&lt;div class="unity-intro__top">
&lt;span class="unity-intro__eyebrow">Getting started · 3D creation&lt;/span>
&lt;img class="unity-intro__logo" src="images/figure-01.png" alt="Unity" width="345" height="146">
&lt;/div>
&lt;dl class="unity-intro__facts">
&lt;div>&lt;dt>Duration&lt;/dt>&lt;dd>2–3 hours&lt;/dd>&lt;/div>
&lt;div>&lt;dt>Environment&lt;/dt>&lt;dd>Unity 6.3 LTS · URP&lt;/dd>&lt;/div>
&lt;div>&lt;dt>Level&lt;/dt>&lt;dd>Unity beginner&lt;/dd>&lt;/div>
&lt;/dl>
&lt;div class="unity-intro__body">&lt;p>A first introduction to Unity for students familiar with computing who have never used the engine. You will build a cube scene, add physics and interactions, navigate in first person, launch objects, import a car and build an executable.&lt;/p>
&lt;p>&lt;strong>Unity 6.3 LTS (6000.3) must be installed.&lt;/strong> Project creation, package installation and resource imports take place during the session. Completion time will depend on your C# experience.&lt;/p>
&lt;/div>
&lt;div class="unity-intro__links">
&lt;a class="unity-intro__card" href="resources-unity63.zip">
&lt;span class="unity-intro__card-label">Lab files&lt;/span>
&lt;strong>Download resources &lt;span aria-hidden="true">↓&lt;/span>&lt;/strong>
&lt;span>Ground texture and car model · ZIP&lt;/span>
&lt;/a>
&lt;a class="unity-intro__card" href="../../tutorial/rapport-tp/">
&lt;span class="unity-intro__card-label">Read first&lt;/span>
&lt;strong>Lab report guidelines &lt;span aria-hidden="true">↗&lt;/span>&lt;/strong>
&lt;span>Report expectations and outline&lt;/span>
&lt;/a>
&lt;/div>
&lt;div class="unity-intro__references">
&lt;span>Documentation&lt;/span>
&lt;a href="https://docs.unity3d.com/6000.3/Documentation/Manual/">Unity 6.3 manual&lt;/a>
&lt;a href="https://learn.unity.com/">Unity Learn&lt;/a>
&lt;/div>
&lt;p class="unity-intro__campus">&lt;span>Brest campus only&lt;/span> &lt;a href="../../tutorial/unity-instructions-pc-ecole/">School PC configuration &lt;span aria-hidden="true">→&lt;/span>&lt;/a>&lt;/p>
&lt;details class="unity-intro__help">
&lt;summary>Definitions throughout the lab&lt;/summary>
&lt;p>Terms with a dotted underline have a definition: hover over or click them. You can also reach them with Tab and use Enter or Space; Escape closes the tooltip.&lt;/p>
&lt;/details>
&lt;details class="unity-intro__outline">
&lt;summary>Lab outline&lt;/summary>
&lt;nav id="TableOfContents">
&lt;ul>
&lt;li>&lt;a href="#prepare-the-project">Prepare the project&lt;/a>&lt;/li>
&lt;li>&lt;a href="#the-unity-3d-editor">The Unity 3D Editor&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#fundamental-concepts">Fundamental concepts&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#create-a-simple-scene">Create a simple scene&lt;/a>&lt;/li>
&lt;li>&lt;a href="#animate-a-scene-object">Animate a scene object&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#write-rotatecube">Write RotateCube&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#input-and-interactions">Input and interactions&lt;/a>&lt;/li>
&lt;li>&lt;a href="#simple-mouse-interaction">Simple mouse interaction&lt;/a>&lt;/li>
&lt;li>&lt;a href="#navigation-by-reusing-keyboardmouse-interaction-scripts">Navigation by reusing keyboard/mouse interaction scripts&lt;/a>&lt;/li>
&lt;li>&lt;a href="#dynamic-object-creation">Dynamic object creation&lt;/a>&lt;/li>
&lt;li>&lt;a href="#load-a-mesh">Load a mesh&lt;/a>&lt;/li>
&lt;li>&lt;a href="#build-an-executable">Build an executable&lt;/a>&lt;/li>
&lt;li>&lt;a href="#going-further">Going further&lt;/a>&lt;/li>
&lt;li>&lt;a href="#resources">Resources&lt;/a>&lt;/li>
&lt;li>&lt;a href="#troubleshooting">Troubleshooting&lt;/a>&lt;/li>
&lt;/ul>
&lt;/nav>
&lt;/details>
&lt;/section>
&lt;h2 id="prepare-the-project">Prepare the project&lt;/h2>
&lt;ol>
&lt;li>In &lt;button type="button" class="unity-term" popovertarget="unity-term-1" popovertargetaction="show" aria-describedby="unity-term-1">Unity Hub&lt;/button>&lt;span id="unity-term-1" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Unity Hub&lt;/strong>&lt;span>Application for creating and opening Unity projects and managing installed editor versions.&lt;/span>&lt;/span>
, select &lt;strong>6.3 LTS&lt;/strong> and create a &lt;strong>Universal 3D&lt;/strong> (&lt;button type="button" class="unity-term" popovertarget="unity-term-2" popovertargetaction="show" aria-describedby="unity-term-2">URP&lt;/button>&lt;span id="unity-term-2" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>URP&lt;/strong>&lt;span>Universal Render Pipeline: Unity’s rendering system for turning a scene into images. Materials must use URP-compatible shaders.&lt;/span>&lt;/span>
) project. Use the same &lt;code>6000.3.xf1&lt;/code> patch throughout the session. The &lt;button type="button" class="unity-term" popovertarget="unity-term-3" popovertargetaction="show" aria-describedby="unity-term-3">materials&lt;/button>&lt;span id="unity-term-3" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Material&lt;/strong>&lt;span>An asset describing a surface’s appearance by combining a shader with parameters such as color and textures.&lt;/span>&lt;/span>
and controller used here target URP.&lt;/li>
&lt;li>&lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-4" popovertargetaction="show" aria-describedby="unity-term-4">Assets&lt;/button>&lt;span id="unity-term-4" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Asset&lt;/strong>&lt;span>A resource stored in the project: a scene, script, texture, material, model or prefab. Multiple objects can use it.&lt;/span>&lt;/span>
&lt;/strong> are your project resources: scenes, &lt;button type="button" class="unity-term" popovertarget="unity-term-5" popovertargetaction="show" aria-describedby="unity-term-5">scripts&lt;/button>&lt;span id="unity-term-5" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Script&lt;/strong>&lt;span>A C# project file. A script derived from MonoBehaviour can be attached to a GameObject as a component.&lt;/span>&lt;/span>
, materials, &lt;button type="button" class="unity-term" popovertarget="unity-term-6" popovertargetaction="show" aria-describedby="unity-term-6">textures&lt;/button>&lt;span id="unity-term-6" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Texture&lt;/strong>&lt;span>An image used by a material to add surface detail, such as color or apparent relief. A texture alone does not define the complete appearance.&lt;/span>&lt;/span>
, &lt;button type="button" class="unity-term" popovertarget="unity-term-7" popovertargetaction="show" aria-describedby="unity-term-7">3D models&lt;/button>&lt;span id="unity-term-7" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>3D model&lt;/strong>&lt;span>An imported resource containing geometry and possibly materials, a hierarchy or animations.&lt;/span>&lt;/span>
and &lt;button type="button" class="unity-term" popovertarget="unity-term-8" popovertargetaction="show" aria-describedby="unity-term-8">prefabs&lt;/button>&lt;span id="unity-term-8" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Prefab&lt;/strong>&lt;span>A reusable GameObject template asset with components and children. Instances inherit template changes unless settings are locally overridden.&lt;/span>&lt;/span>
. They are stored in the &lt;strong>Assets&lt;/strong> folder shown in the &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-9" popovertargetaction="show" aria-describedby="unity-term-9">Project&lt;/button>&lt;span id="unity-term-9" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Project&lt;/strong>&lt;span>Editor window showing project files and assets. Unlike Hierarchy, it does not list just the objects in the scene.&lt;/span>&lt;/span>
&lt;/strong> window. Organize them by creating &lt;code>Scenes&lt;/code>, &lt;code>Materials&lt;/code>, &lt;code>Textures&lt;/code>, &lt;code>Prefabs&lt;/code> and &lt;code>Scripts&lt;/code> through &lt;strong>right-click in Assets &amp;gt; Create &amp;gt; Folder&lt;/strong>; reuse &lt;code>Scenes&lt;/code> if it already exists. In Project, find the open scene (usually &lt;code>SampleScene&lt;/code>), rename it &lt;strong>UnityBasics&lt;/strong> using &lt;strong>Rename&lt;/strong> (or F2), and move it into &lt;code>Assets/Scenes&lt;/code> if needed. Save the scene with &lt;strong>Ctrl+S&lt;/strong>.&lt;/li>
&lt;li>Open &lt;strong>Window &amp;gt; Package Management &amp;gt; &lt;button type="button" class="unity-term" popovertarget="unity-term-10" popovertargetaction="show" aria-describedby="unity-term-10">Package Manager&lt;/button>&lt;span id="unity-term-10" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Package Manager&lt;/strong>&lt;span>Window for finding, installing and managing packages and importing assets from your account.&lt;/span>&lt;/span>
&lt;/strong>. In &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-11" popovertargetaction="show" aria-describedby="unity-term-11">Unity Registry&lt;/button>&lt;span id="unity-term-11" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Unity Registry&lt;/strong>&lt;span>Unity’s package catalog, available through the Package Manager.&lt;/span>&lt;/span>
&lt;/strong>, search for &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-12" popovertargetaction="show" aria-describedby="unity-term-12">Input System&lt;/button>&lt;span id="unity-term-12" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Input System&lt;/strong>&lt;span>Package that receives keyboard, mouse or gamepad input and maps it to application actions.&lt;/span>&lt;/span>
&lt;/strong> (&lt;code>com.unity.inputsystem&lt;/code>) and click &lt;strong>Install&lt;/strong> if it is not installed. The version used when testing this lab is &lt;strong>1.20.0&lt;/strong>. Under &lt;strong>Edit &amp;gt; Project Settings &amp;gt; Player &amp;gt; Other Settings &amp;gt; Configuration &amp;gt; &lt;button type="button" class="unity-term" popovertarget="unity-term-13" popovertargetaction="show" aria-describedby="unity-term-13">Active Input Handling&lt;/button>&lt;span id="unity-term-13" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Active Input Handling&lt;/strong>&lt;span>Project setting selecting enabled input systems: Input System, the legacy Input Manager or both.&lt;/span>&lt;/span>
&lt;/strong>, select &lt;strong>Input System Package (New)&lt;/strong> &lt;strong>only if it is not already selected&lt;/strong>, then accept the requested restart. Under &lt;strong>In Project&lt;/strong> in the Package Manager, check that &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-14" popovertargetaction="show" aria-describedby="unity-term-14">Unity UI&lt;/button>&lt;span id="unity-term-14" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Unity UI / uGUI&lt;/strong>&lt;span>Unity’s GameObject-based UI system. It also provides the EventSystem and pointer event interfaces used here.&lt;/span>&lt;/span>
&lt;/strong> (&lt;code>com.unity.ugui&lt;/code>) is installed: it provides the &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-15" popovertargetaction="show" aria-describedby="unity-term-15">EventSystem&lt;/button>&lt;span id="unity-term-15" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>EventSystem&lt;/strong>&lt;span>Component that distributes interaction events to the relevant objects using an input module and raycasters.&lt;/span>&lt;/span>
&lt;/strong>, &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-16" popovertargetaction="show" aria-describedby="unity-term-16">Physics Raycaster&lt;/button>&lt;span id="unity-term-16" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Physics Raycaster&lt;/strong>&lt;span>Camera component identifying 3D colliders under the pointer and providing these results to the EventSystem.&lt;/span>&lt;/span>
&lt;/strong> and click/hover interfaces used later. If missing, find it in &lt;strong>Unity Registry&lt;/strong> and install it.&lt;/li>
&lt;li>Add the &lt;a href="https://assetstore.unity.com/packages/3d/characters/first-person-third-person-character-controllers-196526" target="_blank" rel="noopener">official first/third person controller&lt;/a> to your account and import it through &lt;strong>My Assets&lt;/strong> in the Package Manager. Accept installation of its dependencies when prompted, then return to &lt;code>UnityBasics&lt;/code>.&lt;/li>
&lt;li>Download and extract the &lt;a href="resources-unity63.zip">lab resources (&lt;code>resources-unity63.zip&lt;/code>)&lt;/a>. From your file explorer, drag &lt;code>grid_grey.png&lt;/code> into &lt;code>Assets/Textures&lt;/code> in Project. The archive also contains &lt;code>Ford_Mondeo.zip&lt;/code>: extract it to obtain the &lt;code>Ford_Mondeo&lt;/code> folder, containing &lt;code>car.obj&lt;/code>, &lt;code>car.mtl&lt;/code> and &lt;code>.tga&lt;/code> textures. Keep this folder for &lt;strong>Load a &lt;button type="button" class="unity-term" popovertarget="unity-term-17" popovertargetaction="show" aria-describedby="unity-term-17">mesh&lt;/button>&lt;span id="unity-term-17" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Mesh&lt;/strong>&lt;span>An object’s 3D geometry, described by vertices and faces. The visible mesh and collision shape may differ.&lt;/span>&lt;/span>
&lt;/strong>, where you will import it into Unity as a whole.&lt;/li>
&lt;/ol>
&lt;h2 id="the-unity-3d-editor">The Unity 3D Editor&lt;/h2>
&lt;p>A &lt;button type="button" class="unity-term" popovertarget="unity-term-18" popovertargetaction="show" aria-describedby="unity-term-18">template&lt;/button>&lt;span id="unity-term-18" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Template&lt;/strong>&lt;span>A starting template that creates a project with preconfigured packages and settings.&lt;/span>&lt;/span>
scene generally contains &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-19" popovertargetaction="show" aria-describedby="unity-term-19">Main Camera&lt;/button>&lt;span id="unity-term-19" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Camera&lt;/strong>&lt;span>An object with a Camera component that renders a scene view. Navigating Scene differs from viewing through the game camera.&lt;/span>&lt;/span>
&lt;/strong>, &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-20" popovertargetaction="show" aria-describedby="unity-term-20">Directional Light&lt;/button>&lt;span id="unity-term-20" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Directional Light&lt;/strong>&lt;span>A light shining in a uniform direction, like a distant sun.&lt;/span>&lt;/span>
&lt;/strong> and possibly a &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-21" popovertargetaction="show" aria-describedby="unity-term-21">Global Volume&lt;/button>&lt;span id="unity-term-21" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Global Volume&lt;/strong>&lt;span>An object applying rendering settings, including post-processing effects, globally according to its configuration.&lt;/span>&lt;/span>
&lt;/strong> for URP rendering. Window layouts can vary.&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Editor window landmarks" srcset="
/teaching/lab/intro-unity/images/unity63-editor-numbered_hud0ac6e7e6d72c5576d38b230060eecc7_1472125_8ee180c96def1483d4b4de322d35a05f.webp 400w,
/teaching/lab/intro-unity/images/unity63-editor-numbered_hud0ac6e7e6d72c5576d38b230060eecc7_1472125_037882c13ba931ca2b32db7d1027ae57.webp 760w,
/teaching/lab/intro-unity/images/unity63-editor-numbered_hud0ac6e7e6d72c5576d38b230060eecc7_1472125_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.etiennepeillard.com/teaching/lab/intro-unity/images/unity63-editor-numbered_hud0ac6e7e6d72c5576d38b230060eecc7_1472125_8ee180c96def1483d4b4de322d35a05f.webp"
width="760"
height="616"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;p>&lt;em>Unity 6.3 LTS screenshot. Labels 6 and 7 point to the &lt;button type="button" class="unity-term" popovertarget="unity-term-22" popovertargetaction="show" aria-describedby="unity-term-22">Game&lt;/button>&lt;span id="unity-term-22" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Game&lt;/strong>&lt;span>Window displaying the game cameras’ output and allowing application interactions to be tested.&lt;/span>&lt;/span>
and &lt;button type="button" class="unity-term" popovertarget="unity-term-23" popovertargetaction="show" aria-describedby="unity-term-23">Console&lt;/button>&lt;span id="unity-term-23" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Console&lt;/strong>&lt;span>Window displaying logs, warnings and errors, including C# compilation errors.&lt;/span>&lt;/span>
tabs; click them to display their contents.&lt;/em>&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Number&lt;/th>
&lt;th>Window&lt;/th>
&lt;th>Purpose&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>1&lt;/td>
&lt;td>&lt;button type="button" class="unity-term" popovertarget="unity-term-24" popovertargetaction="show" aria-describedby="unity-term-24">Scene&lt;/button>&lt;span id="unity-term-24" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Scene&lt;/strong>&lt;span>Working view for inspecting and editing the scene independently of the game camera.&lt;/span>&lt;/span>
&lt;/td>
&lt;td>Navigate and manipulate scene objects.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>2&lt;/td>
&lt;td>&lt;button type="button" class="unity-term" popovertarget="unity-term-25" popovertargetaction="show" aria-describedby="unity-term-25">Hierarchy&lt;/button>&lt;span id="unity-term-25" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Hierarchy&lt;/strong>&lt;span>Window listing scene GameObjects and their parent/child relationships.&lt;/span>&lt;/span>
&lt;/td>
&lt;td>View &lt;button type="button" class="unity-term" popovertarget="unity-term-26" popovertargetaction="show" aria-describedby="unity-term-26">GameObjects&lt;/button>&lt;span id="unity-term-26" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>GameObject&lt;/strong>&lt;span>The basic scene object. Components give it functions such as rendering, physics, lighting or scripted behavior.&lt;/span>&lt;/span>
and their parent/child relationships.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>3&lt;/td>
&lt;td>&lt;button type="button" class="unity-term" popovertarget="unity-term-27" popovertargetaction="show" aria-describedby="unity-term-27">Inspector&lt;/button>&lt;span id="unity-term-27" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Inspector&lt;/strong>&lt;span>Window displaying and editing the selected object’s components or an asset’s import settings.&lt;/span>&lt;/span>
&lt;/td>
&lt;td>View and edit all &lt;button type="button" class="unity-term" popovertarget="unity-term-28" popovertargetaction="show" aria-describedby="unity-term-28">components&lt;/button>&lt;span id="unity-term-28" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Component&lt;/strong>&lt;span>An element attached to a GameObject that adds a property or behavior. One object can have several components.&lt;/span>&lt;/span>
, including scripts.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>4&lt;/td>
&lt;td>Project&lt;/td>
&lt;td>View assets: scenes, textures, materials, prefabs, scripts…&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>5&lt;/td>
&lt;td>&lt;button type="button" class="unity-term" popovertarget="unity-term-29" popovertargetaction="show" aria-describedby="unity-term-29">Play&lt;/button>&lt;span id="unity-term-29" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Play mode&lt;/strong>&lt;span>Mode for running the application inside the editor. Scene changes made during execution are normally lost on stopping.&lt;/span>&lt;/span>
/ Pause / Step&lt;/td>
&lt;td>Run, pause and advance execution one frame at a time.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>6&lt;/td>
&lt;td>Game&lt;/td>
&lt;td>View the camera&amp;rsquo;s rendered output.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>7&lt;/td>
&lt;td>Console&lt;/td>
&lt;td>Read messages, warnings and errors.&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="fundamental-concepts">Fundamental concepts&lt;/h3>
&lt;p>Before manipulating objects, take a moment to understand the relationships between project resources, scene objects and their components. The following boxes provide reference points for the session.&lt;/p>
&lt;aside class="unity-concept" role="note" aria-labelledby="unity-concept-30">
&lt;p class="unity-concept__label">Key concept&lt;/p>
&lt;h4 id="unity-concept-30" class="unity-concept__title">The project, assets and instances&lt;/h4>
&lt;div class="unity-concept__body">&lt;p>The &lt;strong>project&lt;/strong> contains the application’s resources and settings. An &lt;strong>asset&lt;/strong> is a saved resource visible in &lt;strong>Project&lt;/strong>: a texture, material, script, 3D model or scene.&lt;/p>
&lt;p>An &lt;strong>instance&lt;/strong> is a copy placed in the scene. Twelve cubes can share a material: editing that asset changes all their appearances; moving one cube in &lt;strong>Hierarchy&lt;/strong> moves only that cube.&lt;/p>
&lt;/div>
&lt;/aside>
&lt;aside class="unity-concept" role="note" aria-labelledby="unity-concept-31">
&lt;p class="unity-concept__label">Key concept&lt;/p>
&lt;h4 id="unity-concept-31" class="unity-concept__title">The scene: organizing a world&lt;/h4>
&lt;div class="unity-concept__body">&lt;p>A &lt;strong>scene&lt;/strong> is an asset that stores a set of GameObjects, their organization and their settings. It can represent a level, room or application screen. &lt;strong>Hierarchy&lt;/strong> shows the objects in the open scene.&lt;/p>
&lt;p>&lt;strong>In this lab:&lt;/strong> &lt;code>UnityBasics&lt;/code> contains the floor, cubes, camera and light. Saving the scene records their arrangement. The &lt;strong>Scene&lt;/strong> window is a working view of this world; &lt;strong>Game&lt;/strong> shows the camera’s output.&lt;/p>
&lt;/div>
&lt;/aside>
&lt;aside class="unity-concept" role="note" aria-labelledby="unity-concept-32">
&lt;p class="unity-concept__label">Key concept&lt;/p>
&lt;h4 id="unity-concept-32" class="unity-concept__title">The GameObject: an object to compose&lt;/h4>
&lt;div class="unity-concept__body">&lt;p>A &lt;strong>GameObject&lt;/strong> is the basic container for a scene object. Its name helps you find it; its functionality comes from attached components. A GameObject can be empty, without visible geometry.&lt;/p>
&lt;p>&lt;strong>In this lab:&lt;/strong> the cube, camera and light are all GameObjects. They have different roles because they contain different components.&lt;/p>
&lt;/div>
&lt;/aside>
&lt;aside class="unity-concept" role="note" aria-labelledby="unity-concept-33">
&lt;p class="unity-concept__label">Key concept&lt;/p>
&lt;h4 id="unity-concept-33" class="unity-concept__title">Components: giving an object its functions&lt;/h4>
&lt;div class="unity-concept__body">&lt;p>A &lt;strong>component&lt;/strong> adds a property or behavior to a GameObject. Unity uses &lt;strong>composition&lt;/strong>: you assemble several components on the same object rather than selecting a single object type that does everything.&lt;/p>
&lt;p>&lt;strong>In this lab:&lt;/strong> a cube contains a Transform, Mesh Filter, Mesh Renderer and Box Collider. You will add a Rigidbody for physics and then your own scripts. The &lt;strong>Inspector&lt;/strong> shows these components; &lt;strong>Add Component&lt;/strong> adds new ones.&lt;/p>
&lt;/div>
&lt;/aside>
&lt;aside class="unity-concept" role="note" aria-labelledby="unity-concept-34">
&lt;p class="unity-concept__label">Key concept&lt;/p>
&lt;h4 id="unity-concept-34" class="unity-concept__title">Transform: position, rotation and scale&lt;/h4>
&lt;div class="unity-concept__body">&lt;p>Every GameObject has a &lt;strong>Transform&lt;/strong>, defining its &lt;strong>position&lt;/strong>, &lt;strong>rotation&lt;/strong> and &lt;strong>scale&lt;/strong>. These settings place and orient the object and change its size.&lt;/p>
&lt;p>&lt;strong>In this lab:&lt;/strong> the floor remains at the origin &lt;code>(0, 0, 0)&lt;/code>. You edit cube Transforms to build the columns, then a script will change their rotation during execution.&lt;/p>
&lt;/div>
&lt;/aside>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Manipulation tools in Unity 6.3" srcset="
/teaching/lab/intro-unity/images/unity63-scene-tools_hu72bbc9834ff13589e627c63ba23c7732_5757_7bf8e4d9c102835589a63de493d930bf.webp 400w,
/teaching/lab/intro-unity/images/unity63-scene-tools_hu72bbc9834ff13589e627c63ba23c7732_5757_4cb0329f4201f8d243a0349fda82a34f.webp 760w,
/teaching/lab/intro-unity/images/unity63-scene-tools_hu72bbc9834ff13589e627c63ba23c7732_5757_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.etiennepeillard.com/teaching/lab/intro-unity/images/unity63-scene-tools_hu72bbc9834ff13589e627c63ba23c7732_5757_7bf8e4d9c102835589a63de493d930bf.webp"
width="49"
height="211"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;p>Select an object and press &lt;strong>F&lt;/strong> in Scene to frame it. Use Move, Rotate and Scale (&lt;strong>W&lt;/strong>, &lt;strong>E&lt;/strong>, &lt;strong>R&lt;/strong>, outside text fields). Hold the right mouse button to look around Scene; movement keys then let you navigate. &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-35" popovertargetaction="show" aria-describedby="unity-term-35">Local/Global&lt;/button>&lt;span id="unity-term-35" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Local / Global&lt;/strong>&lt;span>Local uses the object’s axes; Global uses world axes. A child’s coordinates can also be expressed relative to its parent.&lt;/span>&lt;/span>
&lt;/strong> selects the manipulation coordinate system. See &lt;a href="https://docs.unity3d.com/6000.3/Documentation/Manual/SceneViewNavigation.html" target="_blank" rel="noopener">navigation&lt;/a> and &lt;a href="https://docs.unity3d.com/6000.3/Documentation/Manual/PositioningGameObjects.html" target="_blank" rel="noopener">positioning&lt;/a>.&lt;/p>
&lt;aside class="unity-concept" role="note" aria-labelledby="unity-concept-36">
&lt;p class="unity-concept__label">Key concept&lt;/p>
&lt;h4 id="unity-concept-36" class="unity-concept__title">Edit and Play: build, then test&lt;/h4>
&lt;div class="unity-concept__body">&lt;p>&lt;strong>Edit&lt;/strong> is for building and configuring the scene; &lt;strong>Play&lt;/strong> runs the application inside the editor. Scene object changes made during Play are normally reverted when execution stops.&lt;/p>
&lt;p>&lt;strong>Try it:&lt;/strong> enter Play, move an object and stop. Observe its return to its initial position. Stop Play before making persistent scene changes, then save. Click inside Game before testing input.&lt;/p>
&lt;/div>
&lt;/aside>
&lt;h2 id="create-a-simple-scene">Create a simple scene&lt;/h2>
&lt;p>We will create a floor and a stack of twelve blue cubes.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Add &lt;strong>GameObject &amp;gt; 3D Object &amp;gt; Plane&lt;/strong>, named &lt;code>Ground&lt;/code>, with position &lt;code>(0, 0, 0)&lt;/code>, rotation &lt;code>(0, 0, 0)&lt;/code> and scale &lt;code>(10, 1, 10)&lt;/code>. A plane is 10 × 10 units at scale 1, giving 100 × 100 units here. One unit represents approximately one meter; the plane is finite.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Add a cube &lt;code>Cube&lt;/code>, with scale &lt;code>(1, 1, 1)&lt;/code> and position &lt;code>(0, 3, 0)&lt;/code>.
&lt;aside class="unity-concept" role="note" aria-labelledby="unity-concept-37">
&lt;p class="unity-concept__label">Key concept&lt;/p>
&lt;h4 id="unity-concept-37" class="unity-concept__title">Material, shader and texture: three different roles&lt;/h4>
&lt;div class="unity-concept__body">&lt;p>The &lt;strong>Mesh&lt;/strong> defines geometry. The &lt;strong>Renderer&lt;/strong> displays it using one or more &lt;strong>materials&lt;/strong>. A material is an asset: it selects a &lt;strong>shader&lt;/strong> and supplies parameters such as color and textures.&lt;/p>
&lt;p>The shader calculates the surface’s appearance; a texture is an image used in that calculation. Several materials can use the same texture, and several objects can share a material.&lt;/p>
&lt;p>&lt;strong>In this lab:&lt;/strong> &lt;code>CubeBlue&lt;/code> uses &lt;strong>URP Lit&lt;/strong> with a blue color; &lt;code>GroundGrid&lt;/code> also uses a &lt;strong>Base Map&lt;/strong> texture. The material must use a shader compatible with the project’s URP pipeline.&lt;/p>
&lt;/div>
&lt;/aside>
&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Create &lt;code>CubeBlue&lt;/code> in &lt;code>Assets/Materials&lt;/code> (&lt;strong>Assets &amp;gt; Create &amp;gt; Material&lt;/strong>). Select the &lt;button type="button" class="unity-term" popovertarget="unity-term-38" popovertargetaction="show" aria-describedby="unity-term-38">shader&lt;/button>&lt;span id="unity-term-38" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Shader&lt;/strong>&lt;span>Program calculating a surface’s appearance. A material selects the shader and supplies its parameters and textures.&lt;/span>&lt;/span>
&lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-39" popovertargetaction="show" aria-describedby="unity-term-39">Universal Render Pipeline/Lit&lt;/button>&lt;span id="unity-term-39" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>URP Lit&lt;/strong>&lt;span>URP’s standard shader for lit materials, using color, textures and surface properties.&lt;/span>&lt;/span>
&lt;/strong> and a blue &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-40" popovertargetaction="show" aria-describedby="unity-term-40">Base Map&lt;/button>&lt;span id="unity-term-40" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Base Map&lt;/strong>&lt;span>The base texture and color of a URP Lit material, combined to determine its surface color.&lt;/span>&lt;/span>
&lt;/strong> color. Drag the material onto the cube.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Create &lt;code>GroundGrid&lt;/code>, also using URP Lit, and drag &lt;code>grid_grey.png&lt;/code> into its &lt;strong>Base Map&lt;/strong>. Assign this material to the plane. Click the &lt;code>grid_grey.png&lt;/code> texture in the &lt;strong>Project&lt;/strong> window: its import settings appear in the &lt;strong>Inspector&lt;/strong>. Check that &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-41" popovertargetaction="show" aria-describedby="unity-term-41">Wrap Mode&lt;/button>&lt;span id="unity-term-41" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Wrap Mode&lt;/strong>&lt;span>Texture setting determining what happens outside its normal coordinates. Repeat tiles the image.&lt;/span>&lt;/span>
= Repeat&lt;/strong>; this is normally already selected. If you change it, click &lt;strong>Apply&lt;/strong>. Try material &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-42" popovertargetaction="show" aria-describedby="unity-term-42">Tiling&lt;/button>&lt;span id="unity-term-42" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Tiling&lt;/strong>&lt;span>Material parameter controlling how often the texture repeats across a surface.&lt;/span>&lt;/span>
= (100, 100)&lt;/strong> and adjust it. A material describes appearance; a texture is an image used by a material.
&lt;aside class="unity-concept" role="note" aria-labelledby="unity-concept-43">
&lt;p class="unity-concept__label">Key concept&lt;/p>
&lt;h4 id="unity-concept-43" class="unity-concept__title">Tags: identifying objects in scripts&lt;/h4>
&lt;div class="unity-concept__body">&lt;p>A &lt;strong>tag&lt;/strong> is a label assigned to a GameObject, separate from its name. Scripts can find objects with a specific tag. Each GameObject has one tag; several objects can share it.&lt;/p>
&lt;p>&lt;strong>In this lab:&lt;/strong> &lt;strong>MainCamera&lt;/strong> lets &lt;code>Camera.main&lt;/code> find the active camera. Naming an object “Main Camera” is insufficient: also check its &lt;strong>Tag&lt;/strong> field in the Inspector.&lt;/p>
&lt;/div>
&lt;/aside>
&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Place the camera, for example at &lt;code>(8, 6, -12)&lt;/code> with rotation &lt;code>(20, -30, 0)&lt;/code>. Adjust the framing in Game to see the floor and cube. Keep its &lt;strong>MainCamera&lt;/strong> &lt;button type="button" class="unity-term" popovertarget="unity-term-44" popovertargetaction="show" aria-describedby="unity-term-44">tag&lt;/button>&lt;span id="unity-term-44" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Tag&lt;/strong>&lt;span>A label assigned to a GameObject for identification in scripts. For example, Camera.main finds an active camera tagged MainCamera.&lt;/span>&lt;/span>
.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Example framing" srcset="
/teaching/lab/intro-unity/images/figure-04_hu0d1212bdc90c840bdc8a46a18fb2eaee_281261_2349f77e825b70c89e871ced2d48540e.webp 400w,
/teaching/lab/intro-unity/images/figure-04_hu0d1212bdc90c840bdc8a46a18fb2eaee_281261_16e93c7c2a9fb4adf930190146ec9390.webp 760w,
/teaching/lab/intro-unity/images/figure-04_hu0d1212bdc90c840bdc8a46a18fb2eaee_281261_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.etiennepeillard.com/teaching/lab/intro-unity/images/figure-04_hu0d1212bdc90c840bdc8a46a18fb2eaee_281261_2349f77e825b70c89e871ced2d48540e.webp"
width="760"
height="359"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;aside class="unity-concept" role="note" aria-labelledby="unity-concept-45">
&lt;p class="unity-concept__label">Key concept&lt;/p>
&lt;h4 id="unity-concept-45" class="unity-concept__title">Rendering, detecting contacts and simulating movement&lt;/h4>
&lt;div class="unity-concept__body">&lt;p>These three functions are separate: the &lt;strong>Renderer&lt;/strong> displays an object, the &lt;strong>Collider&lt;/strong> defines its collision shape and the &lt;strong>Rigidbody&lt;/strong> simulates movement under gravity and forces.&lt;/p>
&lt;p>&lt;strong>In this lab:&lt;/strong> the cube already has a Box Collider, but needs a Rigidbody to fall. The floor has a collider and remains stationary without a Rigidbody. A visible object can therefore be walked through if it has no collider.&lt;/p>
&lt;/div>
&lt;/aside>
&lt;ol start="6">
&lt;li>
&lt;p>Add a &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-46" popovertargetaction="show" aria-describedby="unity-term-46">Rigidbody&lt;/button>&lt;span id="unity-term-46" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Rigidbody&lt;/strong>&lt;span>Component allowing the physics engine to simulate an object’s motion, gravity, forces and collisions.&lt;/span>&lt;/span>
&lt;/strong> to the cube using &lt;strong>Add Component&lt;/strong>. Keep &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-47" popovertargetaction="show" aria-describedby="unity-term-47">Use Gravity&lt;/button>&lt;span id="unity-term-47" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Use Gravity&lt;/strong>&lt;span>Rigidbody option enabling gravity on that body.&lt;/span>&lt;/span>
&lt;/strong> enabled and &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-48" popovertargetaction="show" aria-describedby="unity-term-48">Is Kinematic&lt;/button>&lt;span id="unity-term-48" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Is Kinematic&lt;/strong>&lt;span>When enabled, the Rigidbody is controlled by code or animation rather than simulation forces.&lt;/span>&lt;/span>
&lt;/strong> disabled. The cube already has a &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-49" popovertargetaction="show" aria-describedby="unity-term-49">Box Collider&lt;/button>&lt;span id="unity-term-49" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Box Collider&lt;/strong>&lt;span>A box-shaped collider, providing a simple and inexpensive approximation of a cube or object part.&lt;/span>&lt;/span>
&lt;/strong>; the plane also has a &lt;button type="button" class="unity-term" popovertarget="unity-term-50" popovertargetaction="show" aria-describedby="unity-term-50">collider&lt;/button>&lt;span id="unity-term-50" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Collider&lt;/strong>&lt;span>Component defining a collision shape. It can detect contact without rendering geometry.&lt;/span>&lt;/span>
. Run the scene: the cube falls and stays on the floor. The &lt;button type="button" class="unity-term" popovertarget="unity-term-51" popovertargetaction="show" aria-describedby="unity-term-51">Renderer&lt;/button>&lt;span id="unity-term-51" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Renderer&lt;/strong>&lt;span>Component rendering geometry and using materials to determine its appearance.&lt;/span>&lt;/span>
displays the object, the Collider defines its collision shape and the Rigidbody enables physics simulation.
&lt;aside class="unity-concept" role="note" aria-labelledby="unity-concept-52">
&lt;p class="unity-concept__label">Key concept&lt;/p>
&lt;h4 id="unity-concept-52" class="unity-concept__title">Prefabs: reusing an object while keeping the link&lt;/h4>
&lt;div class="unity-concept__body">&lt;p>A &lt;strong>prefab&lt;/strong> is an asset storing a GameObject, its components and children. Each copy placed in the scene is an &lt;strong>instance&lt;/strong> linked to the template. Here, twelve cubes will share &lt;code>CubePrefab&lt;/code>.&lt;/p>
&lt;p>&lt;strong>Two ways to edit the template, outside Play:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>From Project:&lt;/strong> select &lt;code>CubePrefab&lt;/code> to adjust its Inspector settings, or double-click it to edit its structure in &lt;strong>Prefab Mode&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>From an instance:&lt;/strong> change a cube’s &lt;strong>Mass&lt;/strong>, for example. This is a local &lt;strong>override&lt;/strong>. In &lt;strong>Overrides&lt;/strong>, at the top of the Inspector, use &lt;strong>Apply&lt;/strong> to transfer it to the template, or &lt;strong>Apply All&lt;/strong> to transfer all changes.&lt;/li>
&lt;/ul>
&lt;p>Instances inherit template changes unless they have their own override on that property. &lt;strong>Revert&lt;/strong> removes an override to restore the template value. Moving a cube remains specific to that instance.&lt;/p>
&lt;p>&lt;a href="https://docs.unity3d.com/6000.3/Documentation/Manual/PrefabInstanceOverrides.html#apply-overrides-to-the-prefab-asset" target="_blank" rel="noopener">Apply or revert overrides&lt;/a>.&lt;/p>
&lt;/div>
&lt;/aside>
&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Stop Play. Drag the cube from Hierarchy into &lt;code>Assets/Prefabs&lt;/code> and name the asset &lt;code>CubePrefab&lt;/code>. Create &lt;strong>twelve instances&lt;/strong> in &lt;strong>two columns of six cubes that converge toward the top&lt;/strong>, as shown below. Keep scale &lt;code>(1, 1, 1)&lt;/code>, rotation &lt;code>(0, 0, 0)&lt;/code> and Z &lt;code>0&lt;/code> for every cube.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>Tip — when working with many objects:&lt;/strong> &lt;a href="https://docs.unity3d.com/6000.3/Documentation/Manual/Hierarchy.html" target="_blank" rel="noopener">duplication with Ctrl+D (Cmd+D on macOS)&lt;/a>, &lt;a href="https://docs.unity3d.com/6000.3/Documentation/Manual/SelectGameObjects.html" target="_blank" rel="noopener">multiple selection&lt;/a> and &lt;a href="https://docs.unity.com/en-us/engine/6000.3/manual/working-with-gameobjects/unity-components/inspector-manage-components/inspector-numeric-fields" target="_blank" rel="noopener">Inspector numeric expressions such as &lt;code>L(a,b)&lt;/code> for distributing objects evenly&lt;/a> can save time. For this lab’s twelve cubes, simply position the instances to reproduce the shape shown below.&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Two columns of six cubes converging toward the top" srcset="
/teaching/lab/intro-unity/images/stack-inward-columns_hudef1ab08f8ec270ecf0a62b7e828224c_134793_afb75adc385d49c0c840ecedd474f840.webp 400w,
/teaching/lab/intro-unity/images/stack-inward-columns_hudef1ab08f8ec270ecf0a62b7e828224c_134793_543e2d86f1bb74940a386f7308f84108.webp 760w,
/teaching/lab/intro-unity/images/stack-inward-columns_hudef1ab08f8ec270ecf0a62b7e828224c_134793_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.etiennepeillard.com/teaching/lab/intro-unity/images/stack-inward-columns_hudef1ab08f8ec270ecf0a62b7e828224c_134793_afb75adc385d49c0c840ecedd474f840.webp"
width="470"
height="508"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;ol start="8">
&lt;li>Test the stack. Double-click &lt;code>CubePrefab&lt;/code> and change &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-53" popovertargetaction="show" aria-describedby="unity-term-53">Mass&lt;/button>&lt;span id="unity-term-53" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Mass&lt;/strong>&lt;span>Rigidbody mass, affecting response to forces and impulses without making free fall faster by itself.&lt;/span>&lt;/span>
&lt;/strong>, then &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-54" popovertargetaction="show" aria-describedby="unity-term-54">Linear Damping&lt;/button>&lt;span id="unity-term-54" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Linear Damping&lt;/strong>&lt;span>Damping that gradually reduces Rigidbody linear velocity, distinct from contact friction.&lt;/span>&lt;/span>
&lt;/strong>. &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-55" popovertargetaction="show" aria-describedby="unity-term-55">Angular Damping&lt;/button>&lt;span id="unity-term-55" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Angular Damping&lt;/strong>&lt;span>Damping that gradually reduces Rigidbody angular velocity.&lt;/span>&lt;/span>
&lt;/strong> slows rotation. Compare the instances, then restore Mass to &lt;code>1&lt;/code> and Linear Damping to &lt;code>0&lt;/code>.&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>Observe:&lt;/strong> without damping, a larger mass does not make an object fall faster. It changes the response to the same impulse, which you will test later. Contact friction is configured through a &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-56" popovertargetaction="show" aria-describedby="unity-term-56">Physics Material&lt;/button>&lt;span id="unity-term-56" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Physics Material&lt;/strong>&lt;span>Asset defining collider friction and bounce. It does not define the object’s visible color.&lt;/span>&lt;/span>
&lt;/strong> on the Collider and differs from damping. Values changed only on an instance may be &lt;em>&lt;button type="button" class="unity-term" popovertarget="unity-term-57" popovertargetaction="show" aria-describedby="unity-term-57">overrides&lt;/button>&lt;span id="unity-term-57" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Prefab override&lt;/strong>&lt;span>A prefab-instance change overriding a setting inherited from the template.&lt;/span>&lt;/span>
&lt;/em>: inspect them if a prefab change does not propagate.&lt;/p>
&lt;h2 id="animate-a-scene-object">Animate a scene object&lt;/h2>
&lt;p>A C# script derived from &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-58" popovertargetaction="show" aria-describedby="unity-term-58">MonoBehaviour&lt;/button>&lt;span id="unity-term-58" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>MonoBehaviour&lt;/strong>&lt;span>Base class for scripts attachable to GameObjects. Unity calls lifecycle methods such as Update.&lt;/span>&lt;/span>
&lt;/strong> becomes a component. We will create a script that simply rotates the cubes.&lt;/p>
&lt;aside class="unity-concept" role="note" aria-labelledby="unity-concept-59">
&lt;p class="unity-concept__label">Key concept&lt;/p>
&lt;h4 id="unity-concept-59" class="unity-concept__title">From a C# file to a Unity component&lt;/h4>
&lt;div class="unity-concept__body">&lt;p>A script is a &lt;strong>C# asset (&lt;code>.cs&lt;/code>) describing behavior&lt;/strong>. In this lab, it contains a class derived from &lt;strong>MonoBehaviour&lt;/strong>, named after its file: &lt;code>RotateCube.cs&lt;/code> contains &lt;code>public class RotateCube : MonoBehaviour&lt;/code>.&lt;/p>
&lt;p>Save the file and return to Unity: it &lt;strong>compiles the code automatically&lt;/strong>. Fix &lt;strong>Console&lt;/strong> errors before continuing.&lt;/p>
&lt;p>To run, the script must be &lt;strong>attached to a GameObject as a component&lt;/strong>, by drag-and-drop or &lt;strong>Add Component&lt;/strong>. Each cube then has its own component instance and settings. Its &lt;strong>fields&lt;/strong> can be exposed in the Inspector, as you will test with &lt;code>speed&lt;/code>.&lt;/p>
&lt;p>&lt;strong>&lt;code>transform&lt;/code>&lt;/strong> directly accesses the Transform of the GameObject carrying the script: no reference needs assigning to rotate the cube.&lt;/p>
&lt;p>&lt;a href="https://docs.unity3d.com/6000.3/Documentation/Manual/creating-scripts.html" target="_blank" rel="noopener">Create a script&lt;/a> · &lt;a href="https://docs.unity3d.com/6000.3/Documentation/ScriptReference/SerializeField.html" target="_blank" rel="noopener">Expose a field with SerializeField&lt;/a>.&lt;/p>
&lt;/div>
&lt;/aside>
&lt;aside class="unity-concept" role="note" aria-labelledby="unity-concept-60">
&lt;p class="unity-concept__label">Key concept&lt;/p>
&lt;h4 id="unity-concept-60" class="unity-concept__title">Start, Update and the MonoBehaviour lifecycle&lt;/h4>
&lt;div class="unity-concept__body">&lt;p>Unity calls these methods automatically: &lt;strong>you do not need a loop or to call them yourself&lt;/strong>. Keep their names and signatures correct, such as &lt;code>void Start()&lt;/code>; remove unused empty methods.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;code>Start()&lt;/code>: prepare once&lt;/strong>, before the active component’s first Update. Here, you will enable input or store the initial color. Disabling and re-enabling the component does not run Start again.&lt;/li>
&lt;li>&lt;strong>&lt;code>Update()&lt;/code>: act every frame&lt;/strong>, while the component and its GameObject are active. You will rotate the cube using &lt;strong>Time.deltaTime&lt;/strong> and detect shots here.&lt;/li>
&lt;/ul>
&lt;p>For mouse interactions, you will obtain the Renderer or Rigidbody directly using &lt;strong>GetComponent in the method that needs it&lt;/strong>.&lt;/p>
&lt;details>
&lt;summary>For reference: other common methods&lt;/summary>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Method&lt;/th>
&lt;th>When is it called?&lt;/th>
&lt;th>Typical use&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>Awake()&lt;/code>&lt;/td>
&lt;td>Once, on initialization on an active GameObject, before Start; even if the component is disabled.&lt;/td>
&lt;td>Prepare internal references.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>OnEnable()&lt;/code>&lt;/td>
&lt;td>Each time the component becomes enabled on an active GameObject.&lt;/td>
&lt;td>Subscribe to events.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>FixedUpdate()&lt;/code>&lt;/td>
&lt;td>At the fixed physics simulation rate.&lt;/td>
&lt;td>Apply continuous forces to a Rigidbody.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>LateUpdate()&lt;/code>&lt;/td>
&lt;td>Every frame, after Update calls.&lt;/td>
&lt;td>Update a camera after objects move.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>OnDisable()&lt;/code>&lt;/td>
&lt;td>When the component or its GameObject is disabled.&lt;/td>
&lt;td>Remove event subscriptions.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>OnDestroy()&lt;/code>&lt;/td>
&lt;td>When a previously active object is destroyed.&lt;/td>
&lt;td>Release resources owned by the component.&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>Simplified sequence for an active component:&lt;/strong> &lt;code>Awake → OnEnable → Start&lt;/code>, then &lt;code>Update → LateUpdate&lt;/code> every frame. &lt;strong>FixedUpdate runs at its own rate&lt;/strong>: a frame can contain zero, one or several physics steps. This sequence does not specify script order across different GameObjects.&lt;/p>
&lt;/details>
&lt;p>&lt;a href="https://docs.unity3d.com/6000.3/Documentation/Manual/execution-order.html" target="_blank" rel="noopener">Lifecycle and execution order&lt;/a> · &lt;a href="https://docs.unity3d.com/6000.3/Documentation/ScriptReference/MonoBehaviour.html" target="_blank" rel="noopener">MonoBehaviour methods&lt;/a>.&lt;/p>
&lt;/div>
&lt;/aside>
&lt;h3 id="write-rotatecube">Write RotateCube&lt;/h3>
&lt;ol>
&lt;li>In &lt;code>Assets/Scripts&lt;/code>, create &lt;strong>Assets &amp;gt; Create &amp;gt; Scripting &amp;gt; MonoBehaviour Script&lt;/strong>, named &lt;code>RotateCube&lt;/code>. Open it in your C# editor; the class name must match the file.&lt;/li>
&lt;/ol>
&lt;aside class="unity-concept unity-concept--advice" role="note" aria-labelledby="unity-concept-61">
&lt;p class="unity-concept__label">Required check&lt;/p>
&lt;h4 id="unity-concept-61" class="unity-concept__title">Before coding: check autocomplete&lt;/h4>
&lt;div class="unity-concept__body">&lt;p>Wait for the C# editor to load the project. Inside &lt;code>Update()&lt;/code>, try these temporary entries one at a time:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Type&lt;/th>
&lt;th>Expected suggestions&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>transform.&lt;/code>&lt;/td>
&lt;td>&lt;code>Rotate&lt;/code>, &lt;code>position&lt;/code>…&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>Vector3.&lt;/code>&lt;/td>
&lt;td>&lt;code>up&lt;/code>, &lt;code>forward&lt;/code>…&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>Time.&lt;/code>&lt;/td>
&lt;td>&lt;code>deltaTime&lt;/code>…&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>The list must suggest &lt;strong>Unity API members&lt;/strong>, not just words already present in the file. If it does not open automatically, try &lt;strong>Ctrl+Space&lt;/strong>. Remove the test entries before saving.&lt;/p>
&lt;p>&lt;strong>Do not continue until these suggestions work.&lt;/strong> In Unity, check &lt;strong>Edit &amp;gt; Preferences &amp;gt; External Tools &amp;gt; External Script Editor&lt;/strong>, then reopen the script from &lt;strong>Project&lt;/strong>. With VS Code, check that the &lt;strong>Microsoft Unity extension&lt;/strong> and its C# dependencies are enabled. Consult the &lt;a href="../../tutorial/unity-instructions-pc-ecole/">configuration guide&lt;/a> or ask your instructor for help.&lt;/p>
&lt;/div>
&lt;/aside>
&lt;ol start="2">
&lt;li>Declare &lt;strong>&lt;code>speed&lt;/code> as a field of the &lt;code>RotateCube&lt;/code> class&lt;/strong>. Place this declaration &lt;strong>inside the class braces, but outside methods&lt;/strong> such as &lt;code>Start()&lt;/code> and &lt;code>Update()&lt;/code>. This field stores the component’s rotation speed; it is not a method-local variable. The &lt;button type="button" class="unity-term" popovertarget="unity-term-62" popovertargetaction="show" aria-describedby="unity-term-62">SerializeField&lt;/button>&lt;span id="unity-term-62" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>SerializeField&lt;/strong>&lt;span>C# attribute allowing Unity to save a private field and expose it in the Inspector.&lt;/span>&lt;/span>
annotation exposes it in the Inspector.&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="na">[SerializeField]&lt;/span> &lt;span class="k">private&lt;/span> &lt;span class="kt">float&lt;/span> &lt;span class="n">speed&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="m">90f&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// degrees per second&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="3">
&lt;li>In &lt;button type="button" class="unity-term" popovertarget="unity-term-63" popovertargetaction="show" aria-describedby="unity-term-63">Update()&lt;/button>&lt;span id="unity-term-63" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Update&lt;/strong>&lt;span>MonoBehaviour method called once per frame while the component is active.&lt;/span>&lt;/span>
, called once per frame, use:&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="n">transform&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Rotate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Vector3&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">up&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">speed&lt;/span> &lt;span class="p">*&lt;/span> &lt;span class="n">Time&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">deltaTime&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Space&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Self&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;button type="button" class="unity-term" popovertarget="unity-term-64" popovertargetaction="show" aria-describedby="unity-term-64">Time.deltaTime&lt;/button>&lt;span id="unity-term-64" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Time.deltaTime&lt;/strong>&lt;span>Duration of the previous frame in seconds. Multiplying speed by it gives the movement or rotation for the current frame.&lt;/span>&lt;/span>
is the elapsed time since the previous frame, making the speed independent of the frame rate. Rotating by 3° per frame would produce different speeds on different machines.&lt;/p>
&lt;ol start="4">
&lt;li>&lt;strong>Test on one cube.&lt;/strong> Select an instance in &lt;strong>Hierarchy&lt;/strong>. Drag &lt;code>RotateCube.cs&lt;/code> from &lt;strong>Project&lt;/strong> onto this cube or into its Inspector; alternatively, click &lt;strong>Add Component&lt;/strong>, search for &lt;strong>RotateCube&lt;/strong> and select it. Check that the component appears in the Inspector. Enter Play: only this cube rotates, because &lt;code>transform&lt;/code> refers to the GameObject the script is attached to.&lt;/li>
&lt;li>&lt;strong>Extend the behavior to the other cubes.&lt;/strong> Stop Play. Adding the component to this instance is an &lt;strong>override&lt;/strong>. In &lt;strong>Overrides&lt;/strong>, at the top of its Inspector, select the added &lt;strong>RotateCube&lt;/strong> component and use &lt;strong>Apply&lt;/strong> to apply it to the prefab. The &lt;code>CubePrefab&lt;/code> template now contains this component and other instances inherit it. Enter Play to see all cubes rotate.&lt;/li>
&lt;li>&lt;strong>Alternatively, edit the template directly.&lt;/strong> Open &lt;code>CubePrefab&lt;/code> from &lt;strong>Project&lt;/strong> and attach RotateCube using the same drag-and-drop or &lt;strong>Add Component&lt;/strong>. To rotate only a few cubes, attach the script to the chosen instances without applying it to the prefab. &lt;strong>Add it only once per cube&lt;/strong>, so two RotateCube components do not combine their rotations.&lt;/li>
&lt;li>Test several speeds in the Inspector. Then, outside Play mode, temporarily replace the declaration with &lt;code>public float speed = 90f;&lt;/code>, followed by &lt;code>private float speed = 90f;&lt;/code>. Save and let Unity compile each time: &lt;strong>does Speed still appear in the Inspector?&lt;/strong> Finish by restoring &lt;code>[SerializeField] private float speed = 90f;&lt;/code>.&lt;/li>
&lt;/ol>
&lt;aside class="unity-concept" role="note" aria-labelledby="unity-concept-65">
&lt;p class="unity-concept__label">Key concept&lt;/p>
&lt;h4 id="unity-concept-65" class="unity-concept__title">Remember: public, private and SerializeField&lt;/h4>
&lt;div class="unity-concept__body">&lt;ul>
&lt;li>&lt;strong>&lt;code>public&lt;/code>&lt;/strong>: accessible to other scripts and visible in the Inspector for a supported type.&lt;/li>
&lt;li>&lt;strong>&lt;code>private&lt;/code>&lt;/strong>: internal to the class and hidden in the Inspector.&lt;/li>
&lt;li>&lt;strong>&lt;code>[SerializeField] private&lt;/code>&lt;/strong>: private in code, but saved by Unity and editable in the Inspector. &lt;strong>This is the recommended choice here.&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Encapsulation:&lt;/strong> keep fields private and expose only useful settings. For communication between scripts, prefer a read-only property or a method controlling the change. The Inspector can still accept an invalid value.&lt;/p>
&lt;p>The Inspector’s saved value takes precedence over the code initializer. Choose &lt;strong>instance or prefab&lt;/strong> according to the intended scope. To keep a setting tested in Play, set it again in Edit mode and save.&lt;/p>
&lt;/div>
&lt;/aside>
&lt;p>&lt;strong>Check:&lt;/strong> the cubes rotate and speed is adjustable in the Inspector without editing code.&lt;/p>
&lt;h2 id="input-and-interactions">Input and interactions&lt;/h2>
&lt;p>&lt;strong>Extend &lt;code>Assets/Scripts/RotateCube.cs&lt;/code>&lt;/strong> so the cube starts stationary and each &lt;strong>R&lt;/strong> press starts or stops its rotation.&lt;/p>
&lt;aside class="unity-concept" role="note" aria-labelledby="unity-concept-66">
&lt;p class="unity-concept__label">Key concept&lt;/p>
&lt;h4 id="unity-concept-66" class="unity-concept__title">An action and its binding&lt;/h4>
&lt;div class="unity-concept__body">An &lt;strong>InputAction&lt;/strong> describes an intent, here &lt;code>ActivateRotation&lt;/code>. Its &lt;strong>binding&lt;/strong> connects it to a control, here R. The &lt;strong>performed&lt;/strong> event notifies your script when the action triggers.&lt;/div>
&lt;/aside>
&lt;ol>
&lt;li>&lt;strong>Import Input System.&lt;/strong> Add &lt;code>using UnityEngine.InputSystem;&lt;/code> at the top of the file, keeping &lt;code>using UnityEngine;&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Declare the action.&lt;/strong> Inside the class, alongside &lt;code>speed&lt;/code> and outside methods, add a private &lt;strong>&lt;code>activateRotation&lt;/code>&lt;/strong> field of type &lt;button type="button" class="unity-term" popovertarget="unity-term-67" popovertargetaction="show" aria-describedby="unity-term-67">InputAction&lt;/button>&lt;span id="unity-term-67" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Input Action&lt;/strong>&lt;span>A logical action such as jumping or rotating, bound to input controls. It can be read or trigger callbacks.&lt;/span>&lt;/span>
, exposed with &lt;code>[SerializeField]&lt;/code>. Initialize it with &lt;code>new InputAction(...)&lt;/code> and these three arguments in order: the name &lt;code>&amp;quot;ActivateRotation&amp;quot;&lt;/code>, the type &lt;code>InputActionType.Button&lt;/code> and the &lt;button type="button" class="unity-term" popovertarget="unity-term-68" popovertargetaction="show" aria-describedby="unity-term-68">binding&lt;/button>&lt;span id="unity-term-68" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Binding&lt;/strong>&lt;span>Mapping between an action and a control, such as the R key or right mouse button.&lt;/span>&lt;/span>
&lt;code>&amp;quot;&amp;lt;Keyboard&amp;gt;/r&amp;quot;&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Store the rotation state.&lt;/strong> Add a private &lt;strong>&lt;code>rotating&lt;/code>&lt;/strong> field of type &lt;code>bool&lt;/code>, initialized to &lt;code>false&lt;/code>. It indicates whether the cube should rotate; it does not need to appear in the Inspector. Keep the existing &lt;code>speed&lt;/code> field.&lt;/li>
&lt;li>&lt;strong>Write the toggle method.&lt;/strong> Add a private &lt;strong>&lt;code>ToggleRotation&lt;/code>&lt;/strong> method that returns &lt;code>void&lt;/code> and takes an &lt;code>InputAction.CallbackContext context&lt;/code> parameter. In its body, assign &lt;code>rotating&lt;/code> the opposite of its current value using the &lt;strong>&lt;code>!&lt;/code>&lt;/strong> operator: &lt;code>false&lt;/code> becomes &lt;code>true&lt;/code>, and vice versa. Input System supplies &lt;code>context&lt;/code>; you do not need to use it here.&lt;/li>
&lt;li>&lt;strong>Subscribe in &lt;code>Start()&lt;/code>.&lt;/strong> Subscribe &lt;code>ToggleRotation&lt;/code> to the &lt;strong>&lt;code>performed&lt;/code>&lt;/strong> event of &lt;code>activateRotation&lt;/code> using &lt;strong>&lt;code>+=&lt;/code>&lt;/strong>, writing the method name without parentheses. This subscription specifies which method to call when the action triggers.&lt;/li>
&lt;/ol>
&lt;aside class="unity-concept" role="note" aria-labelledby="unity-concept-69">
&lt;p class="unity-concept__label">Key concept&lt;/p>
&lt;h4 id="unity-concept-69" class="unity-concept__title">Subscribing to an event with &amp;#43;=&lt;/h4>
&lt;div class="unity-concept__body">&lt;p>For a C# event, &lt;strong>&lt;code>+=&lt;/code> adds a method to call when the event occurs&lt;/strong>: this is a &lt;em>subscription&lt;/em>. Provide the method name without parentheses so it can be called later. &lt;strong>&lt;code>-=&lt;/code>&lt;/strong> removes the subscription.&lt;/p>
&lt;p>An InputAction offers three events:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;code>started&lt;/code>&lt;/strong>: the interaction begins.&lt;/li>
&lt;li>&lt;strong>&lt;code>performed&lt;/code>&lt;/strong>: the action triggers according to its configuration.&lt;/li>
&lt;li>&lt;strong>&lt;code>canceled&lt;/code>&lt;/strong>: the action is canceled or returns to rest.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>For our R button, subscribe only &lt;code>performed&lt;/code> to &lt;code>ToggleRotation&lt;/code>&lt;/strong>: with the default press behavior, the method is called on pressing, without toggling again on release.&lt;/p>
&lt;/div>
&lt;/aside>
&lt;ol start="6">
&lt;li>&lt;strong>Enable the action in &lt;code>Start()&lt;/code>.&lt;/strong> After subscribing, call &lt;strong>&lt;code>Enable()&lt;/code> on &lt;code>activateRotation&lt;/code>&lt;/strong>. This second statement allows the action to receive input: &lt;strong>subscribing alone is not enough&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>Make rotation conditional in &lt;code>Update()&lt;/code>.&lt;/strong> Keep the previous exercise’s &lt;code>transform.Rotate(...)&lt;/code> statement, but place it inside an &lt;strong>&lt;code>if&lt;/code>&lt;/strong> that checks &lt;code>rotating&lt;/code>. The cube then rotates only when this boolean is &lt;code>true&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Check in Unity.&lt;/strong> Save, wait for compilation and inspect the &lt;strong>RotateCube&lt;/strong> component: its action should be &lt;strong>Button&lt;/strong>, bound to R. These settings are the initial values provided by the code. As with &lt;strong>Speed&lt;/strong>, you can edit them in the Inspector; editing a prefab instance creates an &lt;strong>override&lt;/strong>. For this test, keep R and the default press behavior.&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>Check:&lt;/strong> enter Play and click inside Game. Cubes start stationary; pressing R makes them rotate, releasing R changes nothing, and pressing again stops them.&lt;/p>
&lt;aside class="unity-concept unity-concept--try" role="note" aria-labelledby="unity-concept-70">
&lt;p class="unity-concept__label">Try it&lt;/p>
&lt;h4 id="unity-concept-70" class="unity-concept__title">Optional variation: hold R to rotate&lt;/h4>
&lt;div class="unity-concept__body">&lt;p>Adapt the script so cubes rotate &lt;strong>only while R is held&lt;/strong>.&lt;/p>
&lt;ul>
&lt;li>Replace the toggle in &lt;code>ToggleRotation&lt;/code> with an assignment of &lt;code>true&lt;/code> to &lt;code>rotating&lt;/code>. You can rename this method &lt;code>StartRotation&lt;/code> and update its &lt;strong>performed&lt;/strong> subscription in &lt;code>Start()&lt;/code>.&lt;/li>
&lt;li>Create a second method, &lt;code>StopRotation&lt;/code>, with the same &lt;code>InputAction.CallbackContext context&lt;/code> parameter type, which assigns &lt;code>false&lt;/code> to &lt;code>rotating&lt;/code>.&lt;/li>
&lt;li>In &lt;code>Start()&lt;/code>, subscribe this second method to &lt;strong>canceled&lt;/strong> using &lt;code>+=&lt;/code>. With our default configuration, this event is emitted when R is released. Keep the &lt;code>Enable()&lt;/code> call and the condition in &lt;code>Update()&lt;/code>.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Test:&lt;/strong> hold R: cubes rotate. Release R: they stop. Press again to repeat.&lt;/p>
&lt;/div>
&lt;/aside>
&lt;p>&lt;a href="https://docs.unity3d.com/Packages/com.unity.inputsystem@1.20/manual/Actions.html" target="_blank" rel="noopener">Action documentation&lt;/a>.&lt;/p>
&lt;h2 id="simple-mouse-interaction">Simple mouse interaction&lt;/h2>
&lt;p>We will make each cube &lt;strong>red while the mouse hovers over it&lt;/strong>, restore its original color when the mouse moves away, and &lt;strong>push it with a left click&lt;/strong>.&lt;/p>
&lt;p>To detect these interactions, we will add an &lt;strong>EventSystem&lt;/strong> to the scene and a &lt;strong>Physics Raycaster&lt;/strong> to the camera. The former dispatches mouse events; the latter identifies the object under the pointer using its colliders. Our &lt;code>MouseInteraction&lt;/code> script will then receive these events through three methods: &lt;strong>&lt;code>OnPointerEnter&lt;/code>&lt;/strong> when hovering begins, &lt;strong>&lt;code>OnPointerExit&lt;/code>&lt;/strong> when it ends, and &lt;strong>&lt;code>OnPointerClick&lt;/code>&lt;/strong> for clicks.&lt;/p>
&lt;ol>
&lt;li>Add &lt;strong>GameObject &amp;gt; UI &amp;gt; Event System&lt;/strong> if missing. Keep &lt;strong>one active EventSystem&lt;/strong>. It must use &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-71" popovertargetaction="show" aria-describedby="unity-term-71">Input System UI Input Module&lt;/button>&lt;span id="unity-term-71" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Input System UI Input Module&lt;/strong>&lt;span>Module translating Input System actions into events distributed by the EventSystem.&lt;/span>&lt;/span>
&lt;/strong>: replace &lt;strong>Standalone Input Module&lt;/strong> if present. Use &lt;strong>Assign Default Actions&lt;/strong> if UI action references are empty.&lt;/li>
&lt;li>Add &lt;strong>Physics Raycaster&lt;/strong> through Add Component on the active camera tagged &lt;strong>MainCamera&lt;/strong>. Cubes must have colliders and belong to a &lt;button type="button" class="unity-term" popovertarget="unity-term-72" popovertargetaction="show" aria-describedby="unity-term-72">layer&lt;/button>&lt;span id="unity-term-72" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Layer&lt;/strong>&lt;span>A GameObject category used to filter rendering, collisions and raycasts. A mask selects multiple layers.&lt;/span>&lt;/span>
included in the raycaster mask.&lt;/li>
&lt;li>Create a &lt;strong>new &lt;code>MouseInteraction.cs&lt;/code> script&lt;/strong> in &lt;code>Assets/Scripts&lt;/code> and complete it in the following steps. Import &lt;code>UnityEngine.EventSystems&lt;/code> and implement the three interfaces &lt;code>IPointerClickHandler&lt;/code>, &lt;code>IPointerEnterHandler&lt;/code> and &lt;code>IPointerExitHandler&lt;/code>. Define &lt;code>OnPointerClick&lt;/code>, &lt;code>OnPointerEnter&lt;/code> and &lt;code>OnPointerExit&lt;/code>, each public, returning &lt;code>void&lt;/code> and taking &lt;code>PointerEventData eventData&lt;/code>.&lt;/li>
&lt;/ol>
&lt;aside class="unity-concept" role="note" aria-labelledby="unity-concept-73">
&lt;p class="unity-concept__label">Key concept&lt;/p>
&lt;h4 id="unity-concept-73" class="unity-concept__title">Reminder: an interface is a contract&lt;/h4>
&lt;div class="unity-concept__body">&lt;p>A &lt;strong>C# interface&lt;/strong> describes methods a class must provide, including their names, parameters and return types. The implementing class writes those methods’ behavior; it can implement multiple interfaces.&lt;/p>
&lt;p>&lt;strong>Syntax:&lt;/strong> after &lt;code>:&lt;/code>, list the base class, then the interfaces separated by commas:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">public&lt;/span> &lt;span class="k">class&lt;/span> &lt;span class="nc">MouseInteraction&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="n">MonoBehaviour&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IPointerClickHandler&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">IPointerEnterHandler&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">IPointerExitHandler&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Inside the class braces, define the methods required by the interfaces.&lt;/p>
&lt;p>&lt;strong>Here:&lt;/strong> &lt;code>IPointerClickHandler&lt;/code> requires an &lt;code>OnPointerClick&lt;/code> method. The EventSystem recognizes this interface and calls that method on a click. You decide what the cube does in its body. The other two interfaces follow the same principle for the beginning and end of hovering.&lt;/p>
&lt;p>&lt;a href="https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/types/interfaces" target="_blank" rel="noopener">Learn more about C# interfaces — Microsoft Learn&lt;/a>.&lt;/p>
&lt;/div>
&lt;/aside>
&lt;ol start="4">
&lt;li>&lt;strong>Prepare the component.&lt;/strong> Initially leave the three interaction methods empty, save and check that the script compiles. Add &lt;strong>MouseInteraction&lt;/strong> to &lt;code>CubePrefab&lt;/code> so every cube has this behavior. All changes below belong in &lt;strong>&lt;code>MouseInteraction.cs&lt;/code>&lt;/strong>. Nothing is needed in &lt;code>Update()&lt;/code>: the interaction methods will be called on mouse events.&lt;/li>
&lt;li>&lt;strong>Remember the starting color.&lt;/strong> Declare a private &lt;strong>&lt;code>initialColor&lt;/code>&lt;/strong> field of type &lt;code>Color&lt;/code> inside the class, outside methods. In &lt;strong>&lt;code>Start()&lt;/code>&lt;/strong>, obtain the cube’s Renderer using &lt;code>gameObject.&lt;/code> followed by &lt;button type="button" class="unity-term" popovertarget="unity-term-74" popovertargetaction="show" aria-describedby="unity-term-74">GetComponent&lt;/button>&lt;span id="unity-term-74" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>GetComponent&lt;/strong>&lt;span>Method finding a component of the requested type on the same GameObject. GetComponentInChildren also searches its children.&lt;/span>&lt;/span>
&lt;code>&amp;lt;Renderer&amp;gt;()&lt;/code>. Then access its &lt;strong>&lt;code>material.color&lt;/code>&lt;/strong> property and store that color in &lt;code>initialColor&lt;/code>. Each cube therefore remembers its own color at startup.&lt;/li>
&lt;li>&lt;strong>Turn the cube red on hover.&lt;/strong> In &lt;strong>&lt;code>OnPointerEnter&lt;/code>&lt;/strong>, obtain the Renderer in the same way and assign &lt;strong>&lt;code>Color.red&lt;/code>&lt;/strong> to its &lt;code>material.color&lt;/code> property. &lt;strong>Test:&lt;/strong> save, enter Play and hover over a cube in Game: only that cube should turn red.&lt;/li>
&lt;li>&lt;strong>Restore the color on exit.&lt;/strong> In &lt;strong>&lt;code>OnPointerExit&lt;/code>&lt;/strong>, assign &lt;strong>&lt;code>initialColor&lt;/code>&lt;/strong> to the same &lt;code>material.color&lt;/code> property instead. &lt;strong>Test:&lt;/strong> move the mouse away from the cube: it should return to its starting color. Use &lt;code>material&lt;/code>, which lets you change this cube’s appearance individually.&lt;/li>
&lt;li>&lt;strong>Push the cube on left click.&lt;/strong> In &lt;strong>&lt;code>OnPointerClick&lt;/code>&lt;/strong>, add an &lt;strong>&lt;code>if&lt;/code>&lt;/strong> comparing &lt;code>eventData.button&lt;/code> to &lt;strong>&lt;code>PointerEventData.InputButton.Left&lt;/code>&lt;/strong>. Inside it, obtain the &lt;strong>Rigidbody&lt;/strong> with &lt;code>gameObject.GetComponent&amp;lt;Rigidbody&amp;gt;()&lt;/code>, then call its &lt;strong>&lt;code>AddForce&lt;/code>&lt;/strong> method with two arguments: the direction &lt;button type="button" class="unity-term" popovertarget="unity-term-75" popovertargetaction="show" aria-describedby="unity-term-75">Camera.main&lt;/button>&lt;span id="unity-term-75" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Camera.main&lt;/strong>&lt;span>Reference to an active camera tagged MainCamera, distinct from a Cinemachine tracking target.&lt;/span>&lt;/span>
&lt;code>.transform.forward&lt;/code> multiplied by &lt;strong>&lt;code>5f&lt;/code>&lt;/strong>, and &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-76" popovertargetaction="show" aria-describedby="unity-term-76">ForceMode.Impulse&lt;/button>&lt;span id="unity-term-76" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>ForceMode.Impulse&lt;/strong>&lt;span>Mode applying an instantaneous push to a Rigidbody, with an effect depending on its mass.&lt;/span>&lt;/span>
&lt;/strong> for a single push. &lt;strong>Test:&lt;/strong> left click pushes the cube in the camera’s viewing direction; right click does not push it.&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>Check:&lt;/strong> only the hovered cube turns red; left click pushes it, right click does not. &lt;a href="https://docs.unity3d.com/6000.3/Documentation/ScriptReference/MonoBehaviour.html" target="_blank" rel="noopener">MonoBehaviour lifecycle&lt;/a>.&lt;/p>
&lt;aside class="unity-concept unity-concept--try" role="note" aria-labelledby="unity-concept-77">
&lt;p class="unity-concept__label">Try it&lt;/p>
&lt;h4 id="unity-concept-77" class="unity-concept__title">Going further: apply force while holding the button&lt;/h4>
&lt;div class="unity-concept__body">&lt;p>Our script applies an &lt;strong>impulse once per click&lt;/strong>: it gives the cube a single push. Now imagine applying a force &lt;strong>as long as the left mouse button remains held&lt;/strong>.&lt;/p>
&lt;p>To adapt the script, store the pressed state in a boolean: &lt;code>IPointerDownHandler&lt;/code> and its &lt;code>OnPointerDown&lt;/code> method can start pushing, while &lt;code>IPointerUpHandler&lt;/code> and &lt;code>OnPointerUp&lt;/code> can stop it on release. In &lt;strong>&lt;code>FixedUpdate()&lt;/code>&lt;/strong>, when this boolean is true, call &lt;code>AddForce&lt;/code> with &lt;strong>&lt;code>ForceMode.Force&lt;/code>&lt;/strong>. Force is then applied on every physics simulation step rather than once in &lt;code>OnPointerClick&lt;/code>; remove the previous impulse to avoid combining both.&lt;/p>
&lt;p>&lt;strong>Compare:&lt;/strong> a brief press and a prolonged press. How do the cube’s movement and the effect of its mass change?&lt;/p>
&lt;/div>
&lt;/aside>
&lt;h2 id="navigation-by-reusing-keyboardmouse-interaction-scripts">Navigation by reusing keyboard/mouse interaction scripts&lt;/h2>
&lt;p>Integrate a first person controller into your scene using the official &lt;strong>&lt;a href="https://assetstore.unity.com/packages/3d/characters/first-person-third-person-character-controllers-196526" target="_blank" rel="noopener">First Person + Third Person | Character Controllers&lt;/a>&lt;/strong> package. It provides the scripts needed to move the character with the keyboard and look around with the mouse.&lt;/p>
&lt;ol>
&lt;li>After importing through &lt;strong>Package Manager &amp;gt; My Assets&lt;/strong>, open &lt;strong>&lt;code>Assets/Starter Assets/Sample/FirstPersonController/Playground.unity&lt;/code>&lt;/strong> in Project, the first person demonstration scene, and test it. Inspect movement, jump, sprint and look bindings in its Input Actions asset: keys depend on its configuration and your keyboard.&lt;/li>
&lt;li>Identify the &lt;strong>character with &lt;button type="button" class="unity-term" popovertarget="unity-term-78" popovertargetaction="show" aria-describedby="unity-term-78">CharacterController&lt;/button>&lt;span id="unity-term-78" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>CharacterController&lt;/strong>&lt;span>Script-driven character movement component with a capsule shape and collision handling, rather than Rigidbody force simulation.&lt;/span>&lt;/span>
&lt;/strong>, the &lt;strong>rendering camera with Camera / &lt;button type="button" class="unity-term" popovertarget="unity-term-79" popovertargetaction="show" aria-describedby="unity-term-79">AudioListener&lt;/button>&lt;span id="unity-term-79" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>AudioListener&lt;/strong>&lt;span>Component representing the scene’s audio listening position, usually on the active camera.&lt;/span>&lt;/span>
/ &lt;button type="button" class="unity-term" popovertarget="unity-term-80" popovertargetaction="show" aria-describedby="unity-term-80">Cinemachine Brain&lt;/button>&lt;span id="unity-term-80" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Cinemachine&lt;/strong>&lt;span>Package controlling camera tracking, framing and transitions. The Unity camera still produces the image.&lt;/span>&lt;/span>
&lt;/strong>, and the &lt;strong>Cinemachine Camera&lt;/strong> controlling tracking. A tracking target such as &lt;code>PlayerCameraRoot&lt;/code> is a Transform; &lt;strong>it is not necessarily the rendering camera&lt;/strong>.&lt;/li>
&lt;li>In &lt;strong>Hierarchy&lt;/strong>, select &lt;strong>MainCamera&lt;/strong>, &lt;strong>PlayerFollowCamera&lt;/strong>, &lt;strong>PlayerCapsule&lt;/strong>, &lt;strong>UI_EventSystem&lt;/strong> and &lt;strong>UI_TouchScreenInput&lt;/strong> together, as outlined in the screenshot below, and copy them. Open &lt;strong>&lt;code>UnityBasics&lt;/code>, the lab’s scene&lt;/strong>, then paste them. Copy these objects together to preserve the first person &lt;button type="button" class="unity-term" popovertarget="unity-term-81" popovertargetaction="show" aria-describedby="unity-term-81">rig&lt;/button>&lt;span id="unity-term-81" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Camera/character rig&lt;/strong>&lt;span>A connected set of objects and components handling character movement and camera tracking.&lt;/span>&lt;/span>
references.&lt;/li>
&lt;/ol>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Objects to copy from the demonstration scene" srcset="
/teaching/lab/intro-unity/images/first-person-objects-to-copy_hu8b0e4f3b2126b182dfe7c755e69b6d40_1395374_46697a23d5bb07de57e7a7d109430a7f.webp 400w,
/teaching/lab/intro-unity/images/first-person-objects-to-copy_hu8b0e4f3b2126b182dfe7c755e69b6d40_1395374_e608f2d41536b420e23c9a9f217ffa84.webp 760w,
/teaching/lab/intro-unity/images/first-person-objects-to-copy_hu8b0e4f3b2126b182dfe7c755e69b6d40_1395374_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.etiennepeillard.com/teaching/lab/intro-unity/images/first-person-objects-to-copy_hu8b0e4f3b2126b182dfe7c755e69b6d40_1395374_46697a23d5bb07de57e7a7d109430a7f.webp"
width="760"
height="458"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;ol start="4">
&lt;li>&lt;strong>Remove duplicates after pasting.&lt;/strong> Disable the GameObject of &lt;code>UnityBasics&lt;/code>’ original fixed camera and keep the &lt;strong>copied MainCamera&lt;/strong>. Delete the &lt;strong>EventSystem created in the previous section&lt;/strong> and keep the &lt;strong>copied UI_EventSystem&lt;/strong>. There must be &lt;strong>one active EventSystem, one active rendering camera tagged MainCamera and one active AudioListener&lt;/strong>. Also keep &lt;strong>PlayerFollowCamera&lt;/strong>, which controls the rendering camera through Cinemachine. Place the character near the stack, for example X &lt;code>0&lt;/code>, Z &lt;code>-8&lt;/code>, with its bottom just above the floor.&lt;/li>
&lt;li>&lt;strong>Test navigation and notice what changed.&lt;/strong> Check that the controller’s ground mask includes the &lt;code>Ground&lt;/code> layer. Enter Play and click inside Game: test movement, look, jump and sprint. The character works, but red hover and cube clicks no longer work as before: the cursor is locked and the new camera does not yet have a raycaster. If the controller produces footstep or jump sounds, identify them too.&lt;/li>
&lt;li>&lt;strong>Restore interactions at the screen center.&lt;/strong> Stop Play. Add &lt;strong>Physics Raycaster to the copied MainCamera&lt;/strong>. Select &lt;strong>UI_EventSystem&lt;/strong> and, in its &lt;strong>Input System UI Input Module&lt;/strong> component, expand &lt;strong>Advanced&lt;/strong> and set &lt;strong>Cursor Lock Behavior = Screen Center&lt;/strong>. Enter Play again with the cursor locked and mouse look enabled: &lt;strong>the cube aimed at in the screen center turns red, and left click pushes it&lt;/strong>. Physics Raycaster now detects the object ahead of you at the image center.&lt;/li>
&lt;li>&lt;strong>Restore a free mouse pointer.&lt;/strong> Stop Play. On &lt;strong>PlayerCapsule&lt;/strong>, in the controller’s input component (&lt;strong>Starter Assets Inputs&lt;/strong>), uncheck &lt;strong>Cursor Locked&lt;/strong> and &lt;strong>Cursor Input For Look&lt;/strong>. Enter Play again: the mouse is visible, moving it no longer turns your head, and you can &lt;strong>hover over and click cubes with the pointer&lt;/strong>, as in the previous section. &lt;strong>Screen Center&lt;/strong> only forces the screen center when the cursor is locked.&lt;/li>
&lt;/ol>
&lt;aside class="unity-concept unity-concept--try" role="note" aria-labelledby="unity-concept-82">
&lt;p class="unity-concept__label">Try it&lt;/p>
&lt;h4 id="unity-concept-82" class="unity-concept__title">Bonus: switch between the two modes&lt;/h4>
&lt;div class="unity-concept__body">&lt;p>Add a &lt;strong>Button InputAction&lt;/strong>, bound to a key of your choice, to alternate between:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Navigation:&lt;/strong> locked cursor, mouse look and interactions at the screen center.&lt;/li>
&lt;li>&lt;strong>Free interaction:&lt;/strong> visible unlocked cursor, mouse look disabled and interactions under the pointer.&lt;/li>
&lt;/ul>
&lt;p>Store the mode in a boolean and toggle it on each press, as with rotation. Update the controller’s &lt;strong>Cursor Locked / Cursor Input For Look&lt;/strong> options together with the actual cursor state through &lt;strong>&lt;code>Cursor.lockState&lt;/code>&lt;/strong> and &lt;strong>&lt;code>Cursor.visible&lt;/code>&lt;/strong>. Keep &lt;strong>Cursor Lock Behavior = Screen Center&lt;/strong> so the same module handles both modes.&lt;/p>
&lt;/div>
&lt;/aside>
&lt;p>&lt;a href="https://docs.unity3d.com/Packages/com.unity.inputsystem@1.20/api/UnityEngine.InputSystem.UI.InputSystemUIInputModule.html#UnityEngine_InputSystem_UI_InputSystemUIInputModule_cursorLockBehavior" target="_blank" rel="noopener">Cursor Lock Behavior configuration&lt;/a>.&lt;/p>
&lt;h2 id="dynamic-object-creation">Dynamic object creation&lt;/h2>
&lt;p>&lt;code>Instantiate&lt;/code> copies a GameObject or a component and its object. Prefabs allow object creation without a hidden template in the scene. We will launch yellow cubes forward on &lt;strong>right click&lt;/strong>.&lt;/p>
&lt;aside class="unity-concept" role="note" aria-labelledby="unity-concept-83">
&lt;p class="unity-concept__label">Key concept&lt;/p>
&lt;h4 id="unity-concept-83" class="unity-concept__title">Instantiation: creating an object at runtime&lt;/h4>
&lt;div class="unity-concept__body">&lt;p>Objects can be placed in the editor or created at runtime with &lt;strong>Instantiate&lt;/strong>. The function creates a new object from a prefab; this object can then have its own position and movement.&lt;/p>
&lt;p>&lt;strong>In this lab:&lt;/strong> &lt;code>ProjectilePrefab&lt;/code> stays an asset in Project. Each right click creates a scene projectile, applies an impulse and schedules its removal with &lt;strong>Destroy&lt;/strong>. Changing this projectile does not change the original template.&lt;/p>
&lt;/div>
&lt;/aside>
&lt;ol>
&lt;li>Create a &lt;code>Projectile&lt;/code> cube, sized &lt;code>(0.25, 0.25, 0.25)&lt;/code>, with a yellow URP Lit material, &lt;strong>Box Collider&lt;/strong> and &lt;strong>Rigidbody&lt;/strong>, mass &lt;code>1&lt;/code>, gravity enabled and Is Kinematic disabled. Turn it into &lt;code>ProjectilePrefab&lt;/code> and remove its scene instance. It has neither &lt;code>RotateCube&lt;/code> nor &lt;code>MouseInteraction&lt;/code>, to avoid copying the targets&amp;rsquo; actions and behaviors.&lt;/li>
&lt;li>In &lt;code>Assets/Scripts&lt;/code>, create a &lt;strong>new &lt;code>CreateOnClick.cs&lt;/code> script&lt;/strong> and attach it to the &lt;strong>camera that actually has Camera&lt;/strong>, rather than the Cinemachine target. Complete this script in the following steps. Declare &lt;code>[SerializeField] private Rigidbody projectilePrefab;&lt;/code> and drag &lt;code>ProjectilePrefab&lt;/code> into that field: this reference provides direct physics access.&lt;/li>
&lt;li>Import &lt;code>UnityEngine.InputSystem&lt;/code> and declare a &lt;strong>Button InputAction named &lt;code>fire&lt;/code>&lt;/strong>, bound to &lt;code>&amp;lt;Mouse&amp;gt;/rightButton&lt;/code>. Enable it in &lt;code>Start()&lt;/code> as before. Here, instead of subscribing to &lt;code>performed&lt;/code>, &lt;strong>query the action in &lt;code>Update()&lt;/code>&lt;/strong> with &lt;strong>&lt;code>fire.WasPressedThisFrame()&lt;/code>&lt;/strong>: this method returns &lt;code>true&lt;/code> only for the frame in which the button has just been pressed.&lt;/li>
&lt;li>&lt;strong>Calculate the starting position.&lt;/strong> In &lt;code>Update()&lt;/code>, put the following operations inside an &lt;strong>&lt;code>if&lt;/code>&lt;/strong> checking the press detected in step 3. Declare a local &lt;strong>&lt;code>Vector3&lt;/code>&lt;/strong> variable named &lt;code>position&lt;/code>: start from the camera’s position (&lt;code>transform.position&lt;/code>) and add its forward direction (&lt;code>transform.forward&lt;/code>) multiplied by &lt;strong>&lt;code>2f&lt;/code>&lt;/strong>. The projectile will appear two units in front of it.&lt;/li>
&lt;li>&lt;strong>Create the projectile.&lt;/strong> Call &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-84" popovertargetaction="show" aria-describedby="unity-term-84">Instantiate&lt;/button>&lt;span id="unity-term-84" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Instantiate&lt;/strong>&lt;span>Unity function creating a new instance of an object or prefab at runtime.&lt;/span>&lt;/span>
&lt;/strong> with three arguments: &lt;code>projectilePrefab&lt;/code>, the calculated position and the camera’s rotation (&lt;code>transform.rotation&lt;/code>). Store the result in a local &lt;strong>&lt;code>Rigidbody&lt;/code> variable named &lt;code>projectile&lt;/code>&lt;/strong> so you can act on this new instance.&lt;/li>
&lt;li>&lt;strong>Launch the projectile.&lt;/strong> As with pushing the cubes, call &lt;strong>&lt;code>AddForce&lt;/code>&lt;/strong> on the newly created Rigidbody. Use the camera’s forward direction multiplied by &lt;strong>&lt;code>12f&lt;/code>&lt;/strong>, with &lt;strong>&lt;code>ForceMode.Impulse&lt;/code>&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>Remove the projectile after a delay.&lt;/strong> Call &lt;strong>&lt;code>Destroy&lt;/code>&lt;/strong> with the instance’s GameObject (&lt;code>projectile.gameObject&lt;/code>) and a delay of &lt;strong>&lt;code>8f&lt;/code>&lt;/strong> seconds. Keep this call inside the same &lt;code>if&lt;/code>: each projectile will have its own lifetime.&lt;/li>
&lt;/ol>
&lt;p>Yellow comes from the prefab material; you can also change the instance renderer&amp;rsquo;s color. Spawning in front of the player avoids creating it inside the character. Also check for free space in front of the camera: two units do not guarantee avoiding a nearby wall.&lt;/p>
&lt;p>&lt;strong>Observe:&lt;/strong> compare trajectories and pushes by changing mass and impulse. An impulse is applied once; a continuous force would be applied at the simulation rate in &lt;button type="button" class="unity-term" popovertarget="unity-term-85" popovertargetaction="show" aria-describedby="unity-term-85">FixedUpdate&lt;/button>&lt;span id="unity-term-85" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>FixedUpdate&lt;/strong>&lt;span>Method called at the fixed physics simulation rate, independently of the display frame rate.&lt;/span>&lt;/span>
. &lt;code>Destroy&lt;/code> removes the object, here after eight seconds. &lt;a href="https://docs.unity3d.com/6000.3/Documentation/ScriptReference/Object.Instantiate.html" target="_blank" rel="noopener">Instantiate&lt;/a>, &lt;a href="https://docs.unity3d.com/6000.3/Documentation/ScriptReference/Rigidbody.AddForce.html" target="_blank" rel="noopener">AddForce&lt;/a>.&lt;/p>
&lt;h2 id="load-a-mesh">Load a mesh&lt;/h2>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Car example" srcset="
/teaching/lab/intro-unity/images/figure-07_hu4e125b8f4165e487f7dd7e5e2cf836b4_277848_55d13e50f43781f7497e88c19ac9463e.webp 400w,
/teaching/lab/intro-unity/images/figure-07_hu4e125b8f4165e487f7dd7e5e2cf836b4_277848_77978052ef49e284645d223b076ebba4.webp 760w,
/teaching/lab/intro-unity/images/figure-07_hu4e125b8f4165e487f7dd7e5e2cf836b4_277848_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.etiennepeillard.com/teaching/lab/intro-unity/images/figure-07_hu4e125b8f4165e487f7dd7e5e2cf836b4_277848_55d13e50f43781f7497e88c19ac9463e.webp"
width="603"
height="469"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Collider example" srcset="
/teaching/lab/intro-unity/images/figure-08_hub90ceb0976398944bc0cce9b6c9b5d2a_458821_7f791f9e3693599bdd4af6ae05257262.webp 400w,
/teaching/lab/intro-unity/images/figure-08_hub90ceb0976398944bc0cce9b6c9b5d2a_458821_75132369433444e58d510fd6c666ef6f.webp 760w,
/teaching/lab/intro-unity/images/figure-08_hub90ceb0976398944bc0cce9b6c9b5d2a_458821_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://www.etiennepeillard.com/teaching/lab/intro-unity/images/figure-08_hub90ceb0976398944bc0cce9b6c9b5d2a_458821_7f791f9e3693599bdd4af6ae05257262.webp"
width="720"
height="555"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;p>Import the &lt;strong>Ford Mondeo&lt;/strong>, make its windows transparent and define its collisions.&lt;/p>
&lt;ol>
&lt;li>Unzip &lt;code>Ford_Mondeo.zip&lt;/code> from the &lt;a href="resources-unity63.zip">lab resources&lt;/a>. The &lt;code>car.obj&lt;/code> file contains the car’s mesh and the &lt;code>.tga&lt;/code> files are its textures.&lt;/li>
&lt;li>In Project, create &lt;code>Assets/Models&lt;/code> (&lt;strong>right-click in Assets &amp;gt; Create &amp;gt; Folder&lt;/strong>). From your file explorer, drag the &lt;strong>entire extracted &lt;code>Ford_Mondeo&lt;/code> folder&lt;/strong> into &lt;code>Assets/Models&lt;/code> in Project. Wait for the import to finish, then drag &lt;strong>&lt;code>car.obj&lt;/code> from Project into Hierarchy&lt;/strong> to create a scene instance. Select this instance and set &lt;strong>Transform &amp;gt; Scale to &lt;code>(0.01, 0.01, 0.01)&lt;/code>&lt;/strong> as a starting point. Check its size against the one-meter cubes, then adjust its size, rotation and position if necessary. &lt;strong>Base Map&lt;/strong> textures should already be assigned.&lt;/li>
&lt;li>&lt;strong>Extract the materials to edit them.&lt;/strong> Select the &lt;strong>&lt;code>car.obj&lt;/code> asset in Project&lt;/strong>, then open the &lt;strong>Materials&lt;/strong> tab of its &lt;strong>Import Settings&lt;/strong> in the Inspector. Materials are included in the model: click &lt;strong>Extract Materials…&lt;/strong> and choose a folder, such as &lt;code>Assets/Materials/Car&lt;/code>. They become material assets you can edit.&lt;/li>
&lt;li>&lt;strong>Make the windows transparent.&lt;/strong> Identify the material used by the windows and select the extracted material in Project. In its Inspector, using the &lt;strong>Universal Render Pipeline/Lit&lt;/strong> shader, set &lt;strong>Surface Type = Transparent&lt;/strong> and &lt;strong>Blending Mode = Alpha&lt;/strong>. Open the &lt;strong>Base Map&lt;/strong> color and reduce its &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-86" popovertargetaction="show" aria-describedby="unity-term-86">alpha (A)&lt;/button>&lt;span id="unity-term-86" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Alpha&lt;/strong>&lt;span>Opacity component: 0 means transparent and 1 opaque. The shader must also be configured for transparency.&lt;/span>&lt;/span>
&lt;/strong> value, for example to &lt;code>0.3&lt;/code>. Observe the window transparency in the scene.&lt;/li>
&lt;li>Launch cubes at the car and try walking through it. A visible mesh does not automatically provide a collider. Add &lt;strong>Box Colliders&lt;/strong> for a simple approximation or &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-87" popovertargetaction="show" aria-describedby="unity-term-87">Mesh Colliders&lt;/button>&lt;span id="unity-term-87" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Mesh Collider&lt;/strong>&lt;span>Collider using a mesh as its collision shape. Non-convex shapes suit static scenery; dynamic bodies require other choices.&lt;/span>&lt;/span>
&lt;/strong> on suitable parts of the stationary car.&lt;/li>
&lt;/ol>
&lt;p>A non-&lt;button type="button" class="unity-term" popovertarget="unity-term-88" popovertargetaction="show" aria-describedby="unity-term-88">convex&lt;/button>&lt;span id="unity-term-88" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Convex collider&lt;/strong>&lt;span>Collision shape without concavities. Unity restricts dynamic-body Mesh Colliders; a convex approximation is one possible option.&lt;/span>&lt;/span>
Mesh Collider suits &lt;button type="button" class="unity-term" popovertarget="unity-term-89" popovertargetaction="show" aria-describedby="unity-term-89">static&lt;/button>&lt;span id="unity-term-89" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Static&lt;/strong>&lt;span>Flags telling Unity systems that an object will not move, enabling relevant optimizations or precomputation.&lt;/span>&lt;/span>
scenery without a dynamic Rigidbody. For a moving physical car, prefer compound primitive colliders or convex Mesh Colliders with a Rigidbody on the root. More detailed collisions can cost more computation. &lt;a href="https://docs.unity3d.com/6000.3/Documentation/Manual/mesh-colliders.html" target="_blank" rel="noopener">Mesh Colliders&lt;/a>, &lt;a href="https://docs.unity3d.com/6000.3/Documentation/Manual/urp/lit-shader.html" target="_blank" rel="noopener">URP Lit&lt;/a>.&lt;/p>
&lt;p>&lt;strong>Check:&lt;/strong> plausible scale, visible textures, transparent windows and collisions with the character and projectiles.&lt;/p>
&lt;h2 id="build-an-executable">Build an executable&lt;/h2>
&lt;ol>
&lt;li>Stop Play and save &lt;code>UnityBasics&lt;/code>.&lt;/li>
&lt;li>Open &lt;strong>File &amp;gt; &lt;button type="button" class="unity-term" popovertarget="unity-term-90" popovertargetaction="show" aria-describedby="unity-term-90">Build Profiles&lt;/button>&lt;span id="unity-term-90" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Build Profiles&lt;/strong>&lt;span>Build configurations grouping a target platform and application build settings.&lt;/span>&lt;/span>
&lt;/strong>. Choose &lt;strong>Linux&lt;/strong>, &lt;strong>Windows&lt;/strong> or &lt;strong>macOS&lt;/strong> for your machine and create/activate its profile if needed. The corresponding build module must be installed through Unity Hub.&lt;/li>
&lt;li>In &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-91" popovertargetaction="show" aria-describedby="unity-term-91">Scene List&lt;/button>&lt;span id="unity-term-91" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Scene List&lt;/strong>&lt;span>List of scenes included in a build; the first enabled scene is normally loaded at startup.&lt;/span>&lt;/span>
&lt;/strong>, add the scene using &lt;strong>Add Open Scenes&lt;/strong>. Check that it is enabled and first; remove demonstration scenes. A profile can override the shared list: check the list actually used.&lt;/li>
&lt;li>Click &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-92" popovertargetaction="show" aria-describedby="unity-term-92">Build&lt;/button>&lt;span id="unity-term-92" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Build&lt;/strong>&lt;span>Application produced from the project for a target platform, able to run without the Unity editor.&lt;/span>&lt;/span>
&lt;/strong>, choose a dedicated folder outside &lt;code>Assets&lt;/code>, such as &lt;code>Builds/Linux&lt;/code>, then run the application. &lt;strong>Build And Run&lt;/strong> runs it immediately.&lt;/li>
&lt;li>Test navigation, R, clicks, physics and materials outside the editor. Distribute the &lt;strong>whole build folder&lt;/strong>. Explore &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-93" popovertargetaction="show" aria-describedby="unity-term-93">Player Settings&lt;/button>&lt;span id="unity-term-93" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Player Settings&lt;/strong>&lt;span>Settings for the exported application, including its name, resolution and platform options.&lt;/span>&lt;/span>
&amp;gt; Resolution and Presentation&lt;/strong> for resolution and fullscreen behavior.&lt;/li>
&lt;/ol>
&lt;p>The &lt;strong>Web&lt;/strong> platform also supports a browser build with its module. It requires an HTTP server: directly opening the HTML file is insufficient. Start with a local build in this session. &lt;a href="https://docs.unity3d.com/6000.3/Documentation/Manual/build-profiles.html" target="_blank" rel="noopener">Build Profiles&lt;/a>.&lt;/p>
&lt;h2 id="going-further">Going further&lt;/h2>
&lt;p>Choose one direction to extend &lt;strong>the scene you have just built&lt;/strong>. The variations suggested throughout the lab — holding R, pushing while pressed and switching mouse modes — are a good first step.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Customize shooting.&lt;/strong> Expose projectile impulse, lifetime and spawn distance in the Inspector with &lt;code>[SerializeField]&lt;/code>. Compare settings without changing the code.&lt;/li>
&lt;li>&lt;strong>Build a small course.&lt;/strong> Reuse your prefabs to place obstacles and targets. Use &lt;a href="https://docs.unity3d.com/6000.3/Documentation/Manual/Layers.html" target="_blank" rel="noopener">layers&lt;/a> to choose which objects can collide or be targeted.&lt;/li>
&lt;li>&lt;strong>Give the scene an atmosphere.&lt;/strong> Change the &lt;button type="button" class="unity-term" popovertarget="unity-term-94" popovertargetaction="show" aria-describedby="unity-term-94">skybox&lt;/button>&lt;span id="unity-term-94" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Skybox&lt;/strong>&lt;span>Background representing the scene’s distant environment, often the sky.&lt;/span>&lt;/span>
and lighting in &lt;strong>Window &amp;gt; Rendering &amp;gt; Lighting&lt;/strong>. To go further, study &lt;strong>Static&lt;/strong> objects and &lt;button type="button" class="unity-term" popovertarget="unity-term-95" popovertargetaction="show" aria-describedby="unity-term-95">baked lighting&lt;/button>&lt;span id="unity-term-95" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Baked lighting&lt;/strong>&lt;span>Lighting calculated in advance and stored in resources rather than fully recalculated at runtime.&lt;/span>&lt;/span>
: do not mark moving cubes as static. &lt;a href="https://docs.unity3d.com/6000.3/Documentation/Manual/LightMode-Baked.html" target="_blank" rel="noopener">Baked lighting&lt;/a>.&lt;/li>
&lt;li>&lt;strong>Add a visual effect.&lt;/strong> Create smoke with a &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-96" popovertargetaction="show" aria-describedby="unity-term-96">Particle System&lt;/button>&lt;span id="unity-term-96" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Particle System&lt;/strong>&lt;span>Component animating many small particles to represent smoke, fire or other effects.&lt;/span>&lt;/span>
&lt;/strong>, then adjust emission and lifetime. &lt;a href="https://docs.unity3d.com/6000.3/Documentation/Manual/class-ParticleSystem.html" target="_blank" rel="noopener">Documentation&lt;/a>. Then explore &lt;strong>Visual Effect Graph&lt;/strong> or custom materials with &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-97" popovertargetaction="show" aria-describedby="unity-term-97">Shader Graph&lt;/button>&lt;span id="unity-term-97" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Shader Graph&lt;/strong>&lt;span>Visual tool for creating shaders by connecting nodes instead of writing all shader code.&lt;/span>&lt;/span>
&lt;/strong> for URP.&lt;/li>
&lt;li>&lt;strong>Animate part of the scenery.&lt;/strong> Make a door open using &lt;strong>Animation and &lt;button type="button" class="unity-term" popovertarget="unity-term-98" popovertargetaction="show" aria-describedby="unity-term-98">Animator&lt;/button>&lt;span id="unity-term-98" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Animator&lt;/strong>&lt;span>Component controlling animation playback and transitions through an Animator Controller.&lt;/span>&lt;/span>
&lt;/strong>. For delayed events, explore &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-99" popovertargetaction="show" aria-describedby="unity-term-99">coroutines&lt;/button>&lt;span id="unity-term-99" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>Coroutine&lt;/strong>&lt;span>Method that can pause with yield and resume later, for example after a delay.&lt;/span>&lt;/span>
&lt;/strong>. &lt;a href="https://docs.unity3d.com/6000.3/Documentation/Manual/animeditor-UsingAnimationEditor.html" target="_blank" rel="noopener">Animation&lt;/a>, &lt;a href="https://learn.unity.com/tutorial/coroutines" target="_blank" rel="noopener">coroutines&lt;/a>.&lt;/li>
&lt;li>&lt;strong>Display information on screen.&lt;/strong> Add a UI showing the number of projectiles created. Choose &lt;strong>Unity UI&lt;/strong> or &lt;strong>UI Toolkit&lt;/strong> using the &lt;a href="https://docs.unity3d.com/6000.3/Documentation/Manual/UI-system-compare.html" target="_blank" rel="noopener">UI systems comparison&lt;/a>.&lt;/li>
&lt;/ul>
&lt;p>For a later project, you could also import a &lt;strong>Humanoid&lt;/strong> character and animations, study &lt;strong>Inverse Kinematics&lt;/strong>, compare custom controllers based on &lt;strong>CharacterController&lt;/strong> or &lt;strong>Rigidbody&lt;/strong>, or make a car drivable with &lt;strong>WheelCollider&lt;/strong>. These topics need more time: &lt;a href="https://docs.unity3d.com/6000.3/Documentation/Manual/class-Avatar.html" target="_blank" rel="noopener">Avatar&lt;/a>, &lt;a href="https://docs.unity3d.com/6000.3/Documentation/Manual/InverseKinematics.html" target="_blank" rel="noopener">IK&lt;/a>, &lt;a href="https://docs.unity3d.com/6000.3/Documentation/Manual/WheelColliderTutorial.html" target="_blank" rel="noopener">vehicles&lt;/a>.&lt;/p>
&lt;p>To strengthen your scripts, explore &lt;strong>&lt;button type="button" class="unity-term" popovertarget="unity-term-100" popovertargetaction="show" aria-describedby="unity-term-100">RequireComponent&lt;/button>&lt;span id="unity-term-100" class="unity-term-definition" role="tooltip" popover="auto">&lt;strong>RequireComponent&lt;/strong>&lt;span>C# attribute declaring components a script requires, helping Unity add them when attaching the script.&lt;/span>&lt;/span>
&lt;/strong>, reference checks and managing subscriptions when a component is disabled or destroyed.&lt;/p>
&lt;h2 id="resources">Resources&lt;/h2>
&lt;p>&lt;strong>For understanding and programming:&lt;/strong>&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Need&lt;/th>
&lt;th>Resource&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Look up an editor concept or setting&lt;/td>
&lt;td>&lt;a href="https://docs.unity3d.com/6000.3/Documentation/Manual/" target="_blank" rel="noopener">Unity 6.3 Manual&lt;/a>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Understand a C# method’s arguments&lt;/td>
&lt;td>&lt;a href="https://docs.unity3d.com/6000.3/Documentation/ScriptReference/index.html" target="_blank" rel="noopener">Unity 6.3 Scripting API&lt;/a>: search for &lt;code>Instantiate&lt;/code>, &lt;code>AddForce&lt;/code> or &lt;code>GetComponent&lt;/code>, for example.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Explore actions and bindings&lt;/td>
&lt;td>&lt;a href="https://docs.unity3d.com/Packages/com.unity.inputsystem@1.20/manual/Actions.html" target="_blank" rel="noopener">Input System documentation&lt;/a>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Continue with guided exercises&lt;/td>
&lt;td>&lt;a href="https://learn.unity.com/" target="_blank" rel="noopener">Unity Learn&lt;/a>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Find the files used here&lt;/td>
&lt;td>&lt;a href="resources-unity63.zip">Lab resources&lt;/a> and &lt;a href="https://assetstore.unity.com/packages/3d/characters/first-person-third-person-character-controllers-196526" target="_blank" rel="noopener">first/third person controller&lt;/a>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>To enrich the scene:&lt;/strong> &lt;a href="https://ambientcg.com/" target="_blank" rel="noopener">ambientCG&lt;/a> for textures and materials, &lt;a href="https://polyhaven.com/" target="_blank" rel="noopener">Poly Haven&lt;/a> for HDRIs, textures and models, and &lt;a href="https://www.mixamo.com/" target="_blank" rel="noopener">Mixamo&lt;/a> for characters and animations. Before importing an asset, check its usage conditions and, for a Unity package, &lt;strong>Unity 6.3 / URP&lt;/strong> compatibility.&lt;/p>
&lt;p>&lt;strong>Continue after this lab:&lt;/strong> &lt;a href="../intro-vr/">A first virtual reality application&lt;/a> builds on these foundations to introduce headset tracking, controllers, teleportation and object manipulation with OpenXR and XR Interaction Toolkit.&lt;/p>
&lt;h2 id="troubleshooting">Troubleshooting&lt;/h2>
&lt;p>Start with &lt;strong>Console&lt;/strong>: fix the first red error before testing again. Double-click the message to open the relevant line. When asking for help, provide the lab step, the expected result and the exact message.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Symptom&lt;/th>
&lt;th>What to check&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>No Unity autocomplete&lt;/td>
&lt;td>Repeat the check at the start of &lt;strong>Write RotateCube&lt;/strong>. Check the external editor and its extensions, then reopen the script from Unity.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Script does not compile or cannot be added&lt;/td>
&lt;td>Check file and class names, &lt;code>using&lt;/code> directives, braces and methods required by interfaces.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>R does nothing&lt;/td>
&lt;td>Click inside Game. Check RotateCube is attached and enabled, its binding is R, and &lt;code>Start()&lt;/code> contains both the subscription &lt;strong>and&lt;/strong> &lt;code>Enable()&lt;/code>. Also check &lt;strong>Active Input Handling = Input System Package (New)&lt;/strong>.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>No red hover or click response&lt;/td>
&lt;td>Check the cube’s collider and MouseInteraction, &lt;strong>Physics Raycaster on the active rendering camera&lt;/strong>, and one EventSystem with &lt;strong>Input System UI Input Module&lt;/strong>. When navigating, set &lt;strong>Advanced &amp;gt; Cursor Lock Behavior = Screen Center&lt;/strong> to aim with the locked cursor.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Cube turns red but does not move on click&lt;/td>
&lt;td>Use left click. Check the cube’s Rigidbody, &lt;strong>Is Kinematic&lt;/strong> disabled and the active camera’s &lt;strong>MainCamera&lt;/strong> tag.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>No projectile or missing reference&lt;/td>
&lt;td>Check CreateOnClick on the rendering camera, the right-click action and the &lt;strong>Projectile Prefab&lt;/strong> field. The assigned prefab needs a Rigidbody.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Player passes through the ground or car&lt;/td>
&lt;td>Check their colliders; for the ground, also check its layer and the controller’s ground mask.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Pink material or opaque windows&lt;/td>
&lt;td>Check the &lt;strong>Universal Render Pipeline/Lit&lt;/strong> shader. For windows, edit the extracted material: &lt;strong>Surface Type = Transparent&lt;/strong>, then reduce Base Map alpha.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>A change does not propagate to cubes&lt;/td>
&lt;td>Check whether you edited the prefab or an instance and whether the instance has an override.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Build shows the wrong scene&lt;/td>
&lt;td>Check the active profile’s &lt;strong>Scene List&lt;/strong>: &lt;code>UnityBasics&lt;/code> must be checked and first.&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table></description></item></channel></rss>