Skip to content

Commit d9bbe94

Browse files
committed
[add] tutorials for these examples.
1 parent 7970474 commit d9bbe94

File tree

3 files changed

+459
-3
lines changed

3 files changed

+459
-3
lines changed

docs/tutorials/README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,22 @@ title: "Tutorials Index"
33
document_id: "tutorials-index-2025-10-17"
44
status: "living"
55
created: "2025-10-17T00:20:00Z"
6-
last_updated: "2025-11-25T00:00:00Z"
7-
version: "0.4.0"
6+
last_updated: "2025-12-16T00:00:00Z"
7+
version: "0.5.0"
88
engine_workspace_version: "2023.1.30"
99
wgpu_version: "26.0.1"
1010
shader_backend_default: "naga"
1111
winit_version: "0.29.10"
12-
repo_commit: "2ff0a581af014a754e982881193c36f47e685602"
12+
repo_commit: "797047468a927f1e4ba111b43381a607ac53c0d1"
1313
owners: ["lambda-sh"]
1414
reviewers: ["engine", "rendering"]
1515
tags: ["index", "tutorials", "docs"]
1616
---
1717

1818
This index lists tutorials that teach specific `lambda-rs` tasks through complete, incremental builds.
1919

20+
- Basic Triangle: Vertex‑Only Draw — [basic-triangle.md](basic-triangle.md)
21+
- Push Constants: Draw Multiple 2D Triangles — [push-constants-multiple-triangles.md](push-constants-multiple-triangles.md)
2022
- Uniform Buffers: Build a Spinning Triangle — [uniform-buffers.md](uniform-buffers.md)
2123
- Textured Quad: Sample a 2D Texture — [textured-quad.md](textured-quad.md)
2224
- Textured Cube: 3D Push Constants + 2D Sampling — [textured-cube.md](textured-cube.md)
@@ -26,6 +28,7 @@ This index lists tutorials that teach specific `lambda-rs` tasks through complet
2628
Browse all tutorials in this directory.
2729

2830
Changelog
31+
- 0.5.0 (2025-12-16): Add basic triangle and multi-triangle push constants tutorials; update metadata and commit.
2932
- 0.4.0 (2025-11-25): Add Instanced Quads tutorial; update metadata and commit.
3033
- 0.3.0 (2025-11-17): Add Reflective Room tutorial; update metadata and commit.
3134
- 0.2.0 (2025-11-10): Add links for textured quad and textured cube; update metadata and commit.

docs/tutorials/basic-triangle.md

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
---
2+
title: "Basic Triangle: Vertex‑Only Draw"
3+
document_id: "basic-triangle-tutorial-2025-12-16"
4+
status: "draft"
5+
created: "2025-12-16T00:00:00Z"
6+
last_updated: "2025-12-16T00:00:00Z"
7+
version: "0.1.0"
8+
engine_workspace_version: "2023.1.30"
9+
wgpu_version: "26.0.1"
10+
shader_backend_default: "naga"
11+
winit_version: "0.29.10"
12+
repo_commit: "797047468a927f1e4ba111b43381a607ac53c0d1"
13+
owners: ["lambda-sh"]
14+
reviewers: ["engine", "rendering"]
15+
tags: ["tutorial", "graphics", "triangle", "rust", "wgpu"]
16+
---
17+
18+
## Overview <a name="overview"></a>
19+
20+
This tutorial renders a single 2D triangle using a vertex shader that derives
21+
positions from `gl_VertexIndex`. The implementation uses no vertex buffers and
22+
demonstrates the minimal render pass, pipeline, and command sequence in
23+
`lambda-rs`.
24+
25+
Reference implementation: `crates/lambda-rs/examples/triangle.rs`.
26+
27+
## Table of Contents
28+
29+
- [Overview](#overview)
30+
- [Goals](#goals)
31+
- [Prerequisites](#prerequisites)
32+
- [Requirements and Constraints](#requirements-and-constraints)
33+
- [Data Flow](#data-flow)
34+
- [Implementation Steps](#implementation-steps)
35+
- [Step 1 — Runtime and Component Skeleton](#step-1)
36+
- [Step 2 — Vertex and Fragment Shaders](#step-2)
37+
- [Step 3 — Compile Shaders with `ShaderBuilder`](#step-3)
38+
- [Step 4 — Build Render Pass and Pipeline](#step-4)
39+
- [Step 5 — Issue Render Commands](#step-5)
40+
- [Step 6 — Handle Window Resize](#step-6)
41+
- [Validation](#validation)
42+
- [Notes](#notes)
43+
- [Conclusion](#conclusion)
44+
- [Exercises](#exercises)
45+
- [Changelog](#changelog)
46+
47+
## Goals <a name="goals"></a>
48+
49+
- Render a triangle with a vertex shader driven by `gl_VertexIndex`.
50+
- Learn the minimal `RenderCommand` sequence for a draw.
51+
- Construct a `RenderPass` and `RenderPipeline` using builder APIs.
52+
53+
## Prerequisites <a name="prerequisites"></a>
54+
55+
- The workspace builds: `cargo build --workspace`.
56+
- The `lambda-rs` crate examples run: `cargo run -p lambda-rs --example minimal`.
57+
58+
## Requirements and Constraints <a name="requirements-and-constraints"></a>
59+
60+
- Rendering commands MUST be issued inside an active render pass
61+
(`RenderCommand::BeginRenderPass` ... `RenderCommand::EndRenderPass`).
62+
- The pipeline MUST be set before draw commands (`RenderCommand::SetPipeline`).
63+
- The shader interface MUST match the pipeline configuration (no vertex buffers
64+
are declared for this example).
65+
- Back-face culling MUST be disabled or the triangle winding MUST be adjusted.
66+
Rationale: the example’s vertex positions are defined in clockwise order.
67+
68+
## Data Flow <a name="data-flow"></a>
69+
70+
- CPU builds shaders and pipeline once in `on_attach`.
71+
- CPU emits render commands each frame in `on_render`.
72+
- The GPU generates vertex positions from `gl_VertexIndex` (no vertex buffers).
73+
74+
ASCII diagram
75+
76+
```
77+
Component::on_attach
78+
├─ ShaderBuilder → Shader modules
79+
├─ RenderPassBuilder → RenderPass
80+
└─ RenderPipelineBuilder → RenderPipeline
81+
82+
Component::on_render (each frame)
83+
BeginRenderPass → SetPipeline → SetViewports/Scissors → Draw → EndRenderPass
84+
```
85+
86+
## Implementation Steps <a name="implementation-steps"></a>
87+
88+
### Step 1 — Runtime and Component Skeleton <a name="step-1"></a>
89+
90+
Create an `ApplicationRuntime` and register a `Component` that receives
91+
`on_attach`, `on_render`, and `on_event` callbacks.
92+
93+
```rust
94+
fn main() {
95+
let runtime = ApplicationRuntimeBuilder::new("2D Triangle Demo")
96+
.with_window_configured_as(|window_builder| {
97+
return window_builder
98+
.with_dimensions(1200, 600)
99+
.with_name("2D Triangle Window");
100+
})
101+
.with_component(|runtime, demo: DemoComponent| {
102+
return (runtime, demo);
103+
})
104+
.build();
105+
106+
start_runtime(runtime);
107+
}
108+
```
109+
110+
The runtime drives component lifecycle and calls `on_render` on each frame.
111+
112+
### Step 2 — Vertex and Fragment Shaders <a name="step-2"></a>
113+
114+
The vertex shader generates positions from `gl_VertexIndex` so the draw call
115+
only needs a vertex count of `3`.
116+
117+
```glsl
118+
vec2 positions[3];
119+
positions[0] = vec2(0.0, -0.5);
120+
positions[1] = vec2(-0.5, 0.5);
121+
positions[2] = vec2(0.5, 0.5);
122+
123+
gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
124+
```
125+
126+
The fragment shader outputs a constant color.
127+
128+
### Step 3 — Compile Shaders with `ShaderBuilder` <a name="step-3"></a>
129+
130+
Load shader sources from `crates/lambda-rs/assets/shaders/` and compile them
131+
using `ShaderBuilder`.
132+
133+
```rust
134+
let triangle_vertex = VirtualShader::Source {
135+
source: include_str!("../assets/shaders/triangle.vert").to_string(),
136+
kind: ShaderKind::Vertex,
137+
name: String::from("triangle"),
138+
entry_point: String::from("main"),
139+
};
140+
```
141+
142+
The compiled `Shader` objects are stored in component state and passed to the
143+
pipeline builder during `on_attach`.
144+
145+
### Step 4 — Build Render Pass and Pipeline <a name="step-4"></a>
146+
147+
Construct a `RenderPass` targeting the surface format, then build a pipeline.
148+
Disable culling to ensure the triangle is visible regardless of winding.
149+
150+
```rust
151+
let render_pass = render_pass::RenderPassBuilder::new().build(
152+
render_context.gpu(),
153+
render_context.surface_format(),
154+
render_context.depth_format(),
155+
);
156+
157+
let pipeline = pipeline::RenderPipelineBuilder::new()
158+
.with_culling(pipeline::CullingMode::None)
159+
.build(
160+
render_context.gpu(),
161+
render_context.surface_format(),
162+
render_context.depth_format(),
163+
&render_pass,
164+
&self.vertex_shader,
165+
Some(&self.fragment_shader),
166+
);
167+
```
168+
169+
Attach the created resources to the `RenderContext` and store their IDs.
170+
171+
### Step 5 — Issue Render Commands <a name="step-5"></a>
172+
173+
Emit a pass begin, bind the pipeline, set viewport/scissor, and issue a draw.
174+
175+
```rust
176+
RenderCommand::Draw {
177+
vertices: 0..3,
178+
instances: 0..1,
179+
}
180+
```
181+
182+
This produces one triangle using three implicit vertices.
183+
184+
### Step 6 — Handle Window Resize <a name="step-6"></a>
185+
186+
Track `WindowEvent::Resize` and rebuild the `Viewport` each frame using the
187+
stored dimensions.
188+
189+
The viewport and scissor MUST match the surface dimensions to avoid clipping or
190+
undefined behavior when the window resizes.
191+
192+
## Validation <a name="validation"></a>
193+
194+
- Build: `cargo build --workspace`
195+
- Run: `cargo run -p lambda-rs --example triangle`
196+
- Expected behavior: a window opens and shows a solid-color triangle.
197+
198+
## Notes <a name="notes"></a>
199+
200+
- Culling and winding
201+
- This tutorial disables culling via `.with_culling(CullingMode::None)`.
202+
- If culling is enabled, the vertex order in
203+
`crates/lambda-rs/assets/shaders/triangle.vert` SHOULD be updated to
204+
counter-clockwise winding for a default `front_face = CCW` pipeline.
205+
- Debugging
206+
- If the window is blank, verify that the pipeline is set inside the render
207+
pass and the draw uses `0..3` vertices.
208+
209+
## Conclusion <a name="conclusion"></a>
210+
211+
This tutorial demonstrates the minimal `lambda-rs` rendering path: compile
212+
shaders, build a render pass and pipeline, and issue a draw using
213+
`RenderCommand`s.
214+
215+
## Exercises <a name="exercises"></a>
216+
217+
- Exercise 1: Change the triangle color
218+
- Modify `crates/lambda-rs/assets/shaders/triangle.frag` to output a different
219+
constant color.
220+
- Exercise 2: Enable back-face culling
221+
- Set `.with_culling(CullingMode::Back)` and update the vertex order in
222+
`crates/lambda-rs/assets/shaders/triangle.vert` to counter-clockwise.
223+
- Exercise 3: Add a second triangle
224+
- Issue a second `Draw` and offset positions in the shader for one of the
225+
triangles.
226+
- Exercise 4: Introduce push constants
227+
- Add a push constant color and position and port the shader interface to
228+
match `crates/lambda-rs/examples/triangles.rs`.
229+
- Exercise 5: Replace `gl_VertexIndex` with a vertex buffer
230+
- Create a vertex buffer for positions and update the pipeline and shader
231+
inputs accordingly.
232+
233+
## Changelog <a name="changelog"></a>
234+
235+
- 0.1.0 (2025-12-16): Initial draft aligned with
236+
`crates/lambda-rs/examples/triangle.rs`.

0 commit comments

Comments
 (0)