From 60b44e8de6653f3bbc7d950930f0a6a6f0b222a9 Mon Sep 17 00:00:00 2001 From: ZayadNimrod <32575659+ZayadNimrod@users.noreply.github.com> Date: Sun, 2 Aug 2026 15:08:28 +0100 Subject: [PATCH 1/3] Make normal loading more concise before we assume all models have normals --- .../tutorial9-models/src/resources.rs | 46 ++++++----------- docs/beginner/tutorial9-models/README.md | 49 ++++++++----------- 2 files changed, 35 insertions(+), 60 deletions(-) diff --git a/code/beginner/tutorial9-models/src/resources.rs b/code/beginner/tutorial9-models/src/resources.rs index a4786e15f..c564a01b6 100644 --- a/code/beginner/tutorial9-models/src/resources.rs +++ b/code/beginner/tutorial9-models/src/resources.rs @@ -112,38 +112,22 @@ pub async fn load_model( .into_iter() .map(|m| { let vertices = (0..m.mesh.positions.len() / 3) - .map(|i| { - if m.mesh.normals.is_empty() { - model::ModelVertex { - position: [ - m.mesh.positions[i * 3], - m.mesh.positions[i * 3 + 1], - m.mesh.positions[i * 3 + 2], - ], - tex_coords: [ - m.mesh.texcoords[i * 2], - 1.0 - m.mesh.texcoords[i * 2 + 1], - ], - normal: [0.0, 0.0, 0.0], - } + .map(|i| model::ModelVertex { + position: [ + m.mesh.positions[i * 3], + m.mesh.positions[i * 3 + 1], + m.mesh.positions[i * 3 + 2], + ], + tex_coords: [m.mesh.texcoords[i * 2], 1.0 - m.mesh.texcoords[i * 2 + 1]], + normal: if m.mesh.normals.is_empty() { + [0.0, 0.0, 0.0] } else { - model::ModelVertex { - position: [ - m.mesh.positions[i * 3], - m.mesh.positions[i * 3 + 1], - m.mesh.positions[i * 3 + 2], - ], - tex_coords: [ - m.mesh.texcoords[i * 2], - 1.0 - m.mesh.texcoords[i * 2 + 1], - ], - normal: [ - m.mesh.normals[i * 3], - m.mesh.normals[i * 3 + 1], - m.mesh.normals[i * 3 + 2], - ], - } - } + [ + m.mesh.normals[i * 3], + m.mesh.normals[i * 3 + 1], + m.mesh.normals[i * 3 + 2], + ] + }, }) .collect::>(); diff --git a/docs/beginner/tutorial9-models/README.md b/docs/beginner/tutorial9-models/README.md index 1948e4da1..e67c78ca2 100644 --- a/docs/beginner/tutorial9-models/README.md +++ b/docs/beginner/tutorial9-models/README.md @@ -333,35 +333,26 @@ pub async fn load_model( let meshes = models .into_iter() .map(|m| { - let vertices = (0..m.mesh.positions.len() / 3) - .map(|i| { - if m.mesh.normals.is_empty(){ - model::ModelVertex { - position: [ - m.mesh.positions[i * 3], - m.mesh.positions[i * 3 + 1], - m.mesh.positions[i * 3 + 2], - ], - tex_coords: [m.mesh.texcoords[i * 2], 1.0 - m.mesh.texcoords[i * 2 + 1]], - normal: [0.0, 0.0, 0.0], - } - }else{ - model::ModelVertex { - position: [ - m.mesh.positions[i * 3], - m.mesh.positions[i * 3 + 1], - m.mesh.positions[i * 3 + 2], - ], - tex_coords: [m.mesh.texcoords[i * 2], 1.0 - m.mesh.texcoords[i * 2 + 1]], - normal: [ - m.mesh.normals[i * 3], - m.mesh.normals[i * 3 + 1], - m.mesh.normals[i * 3 + 2], - ], - } - } - }) - .collect::>(); + let vertices = (0..m.mesh.positions.len() / 3) + .map(|i| model::ModelVertex { + position: [ + m.mesh.positions[i * 3], + m.mesh.positions[i * 3 + 1], + m.mesh.positions[i * 3 + 2], + ], + tex_coords: [m.mesh.texcoords[i * 2], 1.0 - m.mesh.texcoords[i * 2 + 1]], + normal: if m.mesh.normals.is_empty() { + [0.0, 0.0, 0.0] + } else { + [ + m.mesh.normals[i * 3], + m.mesh.normals[i * 3 + 1], + m.mesh.normals[i * 3 + 2], + ] + }, + }) + .collect::>(); + let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some(&format!("{:?} Vertex Buffer", file_name)), From a0cd109380969ae627feb03d694e46374fc9523d Mon Sep 17 00:00:00 2001 From: ZayadNimrod <32575659+ZayadNimrod@users.noreply.github.com> Date: Sun, 2 Aug 2026 15:08:28 +0100 Subject: [PATCH 2/3] Make model loading more concise by using `chunks_exact` This avoids the manual indexing we were doing previously so should be a bit more foolproof. It's also a bit shorter. --- .../tutorial9-models/src/resources.rs | 26 +++++++------- .../tutorial10-lighting/src/resources.rs | 24 ++++++------- .../tutorial11-normals/src/resources.rs | 24 ++++++------- .../tutorial12-camera/src/resources.rs | 24 ++++++------- .../tutorial13-hdr/src/resources.rs | 24 ++++++------- docs/beginner/tutorial9-models/README.md | 36 +++++++++---------- .../intermediate/tutorial11-normals/README.md | 24 ++++++------- 7 files changed, 84 insertions(+), 98 deletions(-) diff --git a/code/beginner/tutorial9-models/src/resources.rs b/code/beginner/tutorial9-models/src/resources.rs index c564a01b6..ba80d94ae 100644 --- a/code/beginner/tutorial9-models/src/resources.rs +++ b/code/beginner/tutorial9-models/src/resources.rs @@ -111,22 +111,20 @@ pub async fn load_model( let meshes = models .into_iter() .map(|m| { - let vertices = (0..m.mesh.positions.len() / 3) - .map(|i| model::ModelVertex { - position: [ - m.mesh.positions[i * 3], - m.mesh.positions[i * 3 + 1], - m.mesh.positions[i * 3 + 2], - ], - tex_coords: [m.mesh.texcoords[i * 2], 1.0 - m.mesh.texcoords[i * 2 + 1]], - normal: if m.mesh.normals.is_empty() { + let coords = m + .mesh + .positions + .chunks_exact(3) + .zip(m.mesh.normals.chunks_exact(3)) + .zip(m.mesh.texcoords.chunks_exact(2)); + let vertices = coords + .map(|((position, normals), texcoords)| model::ModelVertex { + position: [position[0], position[1], position[2]], + tex_coords: [texcoords[0], 1.0 - texcoords[1]], + normal: if normals.is_empty() { [0.0, 0.0, 0.0] } else { - [ - m.mesh.normals[i * 3], - m.mesh.normals[i * 3 + 1], - m.mesh.normals[i * 3 + 2], - ] + [normals[0], normals[1], normals[2]] }, }) .collect::>(); diff --git a/code/intermediate/tutorial10-lighting/src/resources.rs b/code/intermediate/tutorial10-lighting/src/resources.rs index 4635fac24..7ffc3defa 100644 --- a/code/intermediate/tutorial10-lighting/src/resources.rs +++ b/code/intermediate/tutorial10-lighting/src/resources.rs @@ -111,19 +111,17 @@ pub async fn load_model( let meshes = models .into_iter() .map(|m| { - let vertices = (0..m.mesh.positions.len() / 3) - .map(|i| model::ModelVertex { - position: [ - m.mesh.positions[i * 3], - m.mesh.positions[i * 3 + 1], - m.mesh.positions[i * 3 + 2], - ], - tex_coords: [m.mesh.texcoords[i * 2], 1.0 - m.mesh.texcoords[i * 2 + 1]], - normal: [ - m.mesh.normals[i * 3], - m.mesh.normals[i * 3 + 1], - m.mesh.normals[i * 3 + 2], - ], + let coords = m + .mesh + .positions + .chunks_exact(3) + .zip(m.mesh.normals.chunks_exact(3)) + .zip(m.mesh.texcoords.chunks_exact(2)); + let vertices = coords + .map(|((position, normals), texcoords)| model::ModelVertex { + position: [position[0], position[1], position[2]], + tex_coords: [texcoords[0], 1.0 - texcoords[1]], + normal: [normals[0], normals[1], normals[2]], }) .collect::>(); diff --git a/code/intermediate/tutorial11-normals/src/resources.rs b/code/intermediate/tutorial11-normals/src/resources.rs index df6e6fa0a..403ba23b1 100644 --- a/code/intermediate/tutorial11-normals/src/resources.rs +++ b/code/intermediate/tutorial11-normals/src/resources.rs @@ -101,19 +101,17 @@ pub async fn load_model( let meshes = models .into_iter() .map(|m| { - let mut vertices = (0..m.mesh.positions.len() / 3) - .map(|i| model::ModelVertex { - position: [ - m.mesh.positions[i * 3], - m.mesh.positions[i * 3 + 1], - m.mesh.positions[i * 3 + 2], - ], - tex_coords: [m.mesh.texcoords[i * 2], 1.0 - m.mesh.texcoords[i * 2 + 1]], - normal: [ - m.mesh.normals[i * 3], - m.mesh.normals[i * 3 + 1], - m.mesh.normals[i * 3 + 2], - ], + let coords = m + .mesh + .positions + .chunks_exact(3) + .zip(m.mesh.normals.chunks_exact(3)) + .zip(m.mesh.texcoords.chunks_exact(2)); + let mut vertices = coords + .map(|((position, normals), texcoords)| model::ModelVertex { + position: [position[0], position[1], position[2]], + tex_coords: [texcoords[0], 1.0 - texcoords[1]], + normal: [normals[0], normals[1], normals[2]], // We'll calculate these later tangent: [0.0; 3], bitangent: [0.0; 3], diff --git a/code/intermediate/tutorial12-camera/src/resources.rs b/code/intermediate/tutorial12-camera/src/resources.rs index df6e6fa0a..403ba23b1 100644 --- a/code/intermediate/tutorial12-camera/src/resources.rs +++ b/code/intermediate/tutorial12-camera/src/resources.rs @@ -101,19 +101,17 @@ pub async fn load_model( let meshes = models .into_iter() .map(|m| { - let mut vertices = (0..m.mesh.positions.len() / 3) - .map(|i| model::ModelVertex { - position: [ - m.mesh.positions[i * 3], - m.mesh.positions[i * 3 + 1], - m.mesh.positions[i * 3 + 2], - ], - tex_coords: [m.mesh.texcoords[i * 2], 1.0 - m.mesh.texcoords[i * 2 + 1]], - normal: [ - m.mesh.normals[i * 3], - m.mesh.normals[i * 3 + 1], - m.mesh.normals[i * 3 + 2], - ], + let coords = m + .mesh + .positions + .chunks_exact(3) + .zip(m.mesh.normals.chunks_exact(3)) + .zip(m.mesh.texcoords.chunks_exact(2)); + let mut vertices = coords + .map(|((position, normals), texcoords)| model::ModelVertex { + position: [position[0], position[1], position[2]], + tex_coords: [texcoords[0], 1.0 - texcoords[1]], + normal: [normals[0], normals[1], normals[2]], // We'll calculate these later tangent: [0.0; 3], bitangent: [0.0; 3], diff --git a/code/intermediate/tutorial13-hdr/src/resources.rs b/code/intermediate/tutorial13-hdr/src/resources.rs index 91478d65d..bc6786944 100644 --- a/code/intermediate/tutorial13-hdr/src/resources.rs +++ b/code/intermediate/tutorial13-hdr/src/resources.rs @@ -102,19 +102,17 @@ pub async fn load_model( let meshes = models .into_iter() .map(|m| { - let mut vertices = (0..m.mesh.positions.len() / 3) - .map(|i| model::ModelVertex { - position: [ - m.mesh.positions[i * 3], - m.mesh.positions[i * 3 + 1], - m.mesh.positions[i * 3 + 2], - ], - tex_coords: [m.mesh.texcoords[i * 2], 1.0 - m.mesh.texcoords[i * 2 + 1]], - normal: [ - m.mesh.normals[i * 3], - m.mesh.normals[i * 3 + 1], - m.mesh.normals[i * 3 + 2], - ], + let coords = m + .mesh + .positions + .chunks_exact(3) + .zip(m.mesh.normals.chunks_exact(3)) + .zip(m.mesh.texcoords.chunks_exact(2)); + let mut vertices = coords + .map(|((position, normals), texcoords)| model::ModelVertex { + position: [position[0], position[1], position[2]], + tex_coords: [texcoords[0], 1.0 - texcoords[1]], + normal: [normals[0], normals[1], normals[2]], // We'll calculate these later tangent: [0.0; 3], bitangent: [0.0; 3], diff --git a/docs/beginner/tutorial9-models/README.md b/docs/beginner/tutorial9-models/README.md index e67c78ca2..57659a866 100644 --- a/docs/beginner/tutorial9-models/README.md +++ b/docs/beginner/tutorial9-models/README.md @@ -333,25 +333,23 @@ pub async fn load_model( let meshes = models .into_iter() .map(|m| { - let vertices = (0..m.mesh.positions.len() / 3) - .map(|i| model::ModelVertex { - position: [ - m.mesh.positions[i * 3], - m.mesh.positions[i * 3 + 1], - m.mesh.positions[i * 3 + 2], - ], - tex_coords: [m.mesh.texcoords[i * 2], 1.0 - m.mesh.texcoords[i * 2 + 1]], - normal: if m.mesh.normals.is_empty() { - [0.0, 0.0, 0.0] - } else { - [ - m.mesh.normals[i * 3], - m.mesh.normals[i * 3 + 1], - m.mesh.normals[i * 3 + 2], - ] - }, - }) - .collect::>(); + let coords = m + .mesh + .positions + .chunks_exact(3) + .zip(m.mesh.normals.chunks_exact(3)) + .zip(m.mesh.texcoords.chunks_exact(2)); + let vertices = coords + .map(|((position, normals), texcoords)| model::ModelVertex { + position: [position[0], position[1], position[2]], + tex_coords: [texcoords[0], 1.0 - texcoords[1]], + normal: if normals.is_empty() { + [0.0, 0.0, 0.0] + } else { + [normals[0], normals[1], normals[2]] + }, + }) + .collect::>(); let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { diff --git a/docs/intermediate/tutorial11-normals/README.md b/docs/intermediate/tutorial11-normals/README.md index 8c14b7892..238a76bdb 100644 --- a/docs/intermediate/tutorial11-normals/README.md +++ b/docs/intermediate/tutorial11-normals/README.md @@ -238,19 +238,17 @@ Now, we can calculate the new tangent and bitangent vectors. Update the mesh gen let meshes = models .into_iter() .map(|m| { - let mut vertices = (0..m.mesh.positions.len() / 3) - .map(|i| model::ModelVertex { - position: [ - m.mesh.positions[i * 3], - m.mesh.positions[i * 3 + 1], - m.mesh.positions[i * 3 + 2], - ], - tex_coords: [m.mesh.texcoords[i * 2], 1.0 - m.mesh.texcoords[i * 2 + 1]], - normal: [ - m.mesh.normals[i * 3], - m.mesh.normals[i * 3 + 1], - m.mesh.normals[i * 3 + 2], - ], + let coords = m + .mesh + .positions + .chunks_exact(3) + .zip(m.mesh.normals.chunks_exact(3)) + .zip(m.mesh.texcoords.chunks_exact(2)); + let mut vertices = coords + .map(|((position, normals), texcoords)| model::ModelVertex { + position: [position[0], position[1], position[2]], + tex_coords: [texcoords[0], 1.0 - texcoords[1]], + normal: [normals[0], normals[1], normals[2]], // We'll calculate these later tangent: [0.0; 3], bitangent: [0.0; 3], From 2d2a6810e62350d44162815bc83766f22cbf1645 Mon Sep 17 00:00:00 2001 From: ZayadNimrod <32575659+ZayadNimrod@users.noreply.github.com> Date: Sun, 2 Aug 2026 15:08:28 +0100 Subject: [PATCH 3/3] DRY up (bi)tangent calculations --- .../tutorial11-normals/src/resources.rs | 55 +++++++------------ .../tutorial12-camera/src/resources.rs | 55 +++++++------------ .../tutorial13-hdr/src/resources.rs | 55 +++++++------------ .../intermediate/tutorial11-normals/README.md | 55 +++++++------------ 4 files changed, 84 insertions(+), 136 deletions(-) diff --git a/code/intermediate/tutorial11-normals/src/resources.rs b/code/intermediate/tutorial11-normals/src/resources.rs index 403ba23b1..1b67d9b0b 100644 --- a/code/intermediate/tutorial11-normals/src/resources.rs +++ b/code/intermediate/tutorial11-normals/src/resources.rs @@ -124,27 +124,21 @@ pub async fn load_model( // Calculate tangents and bitangets. We're going to // use the triangles, so we need to loop through the // indices in chunks of 3 - for c in indices.chunks(3) { - let v0 = vertices[c[0] as usize]; - let v1 = vertices[c[1] as usize]; - let v2 = vertices[c[2] as usize]; + for c in indices.chunks_exact(3) { + let verts = c.iter().map(|i| vertices[*i as usize]); - let pos0: cgmath::Vector3<_> = v0.position.into(); - let pos1: cgmath::Vector3<_> = v1.position.into(); - let pos2: cgmath::Vector3<_> = v2.position.into(); - - let uv0: cgmath::Vector2<_> = v0.tex_coords.into(); - let uv1: cgmath::Vector2<_> = v1.tex_coords.into(); - let uv2: cgmath::Vector2<_> = v2.tex_coords.into(); + let positions: Vec> = + verts.clone().map(|v| v.position.into()).collect::>(); + let uvs: Vec> = + verts.clone().map(|v| v.tex_coords.into()).collect(); // Calculate the edges of the triangle - let delta_pos1 = pos1 - pos0; - let delta_pos2 = pos2 - pos0; - + let delta_pos1 = positions[1] - positions[0]; + let delta_pos2 = positions[2] - positions[0]; // This will give us a direction to calculate the // tangent and bitangent - let delta_uv1 = uv1 - uv0; - let delta_uv2 = uv2 - uv0; + let delta_uv1 = uvs[1] - uvs[0]; + let delta_uv2 = uvs[2] - uvs[0]; // Solving the following system of equations will // give us the tangent and bitangent. @@ -158,24 +152,17 @@ pub async fn load_model( // maps with wgpu texture coordinate system let bitangent = (delta_pos2 * delta_uv1.x - delta_pos1 * delta_uv2.x) * -r; - // We'll use the same tangent/bitangent for each vertex in the triangle - vertices[c[0] as usize].tangent = - (tangent + cgmath::Vector3::from(vertices[c[0] as usize].tangent)).into(); - vertices[c[1] as usize].tangent = - (tangent + cgmath::Vector3::from(vertices[c[1] as usize].tangent)).into(); - vertices[c[2] as usize].tangent = - (tangent + cgmath::Vector3::from(vertices[c[2] as usize].tangent)).into(); - vertices[c[0] as usize].bitangent = - (bitangent + cgmath::Vector3::from(vertices[c[0] as usize].bitangent)).into(); - vertices[c[1] as usize].bitangent = - (bitangent + cgmath::Vector3::from(vertices[c[1] as usize].bitangent)).into(); - vertices[c[2] as usize].bitangent = - (bitangent + cgmath::Vector3::from(vertices[c[2] as usize].bitangent)).into(); - - // Used to average the tangents/bitangents - triangles_included[c[0] as usize] += 1; - triangles_included[c[1] as usize] += 1; - triangles_included[c[2] as usize] += 1; + for i in 0..3 { + // We'll use the same tangent/bitangent for each vertex in the triangle + vertices[c[i] as usize].tangent = + (tangent + cgmath::Vector3::from(vertices[c[i] as usize].tangent)).into(); + vertices[c[1] as usize].bitangent = (bitangent + + cgmath::Vector3::from(vertices[c[1] as usize].bitangent)) + .into(); + + // Used to average the tangents/bitangents + triangles_included[c[i] as usize] += 1; + } } // Average the tangents/bitangents diff --git a/code/intermediate/tutorial12-camera/src/resources.rs b/code/intermediate/tutorial12-camera/src/resources.rs index 403ba23b1..1b67d9b0b 100644 --- a/code/intermediate/tutorial12-camera/src/resources.rs +++ b/code/intermediate/tutorial12-camera/src/resources.rs @@ -124,27 +124,21 @@ pub async fn load_model( // Calculate tangents and bitangets. We're going to // use the triangles, so we need to loop through the // indices in chunks of 3 - for c in indices.chunks(3) { - let v0 = vertices[c[0] as usize]; - let v1 = vertices[c[1] as usize]; - let v2 = vertices[c[2] as usize]; + for c in indices.chunks_exact(3) { + let verts = c.iter().map(|i| vertices[*i as usize]); - let pos0: cgmath::Vector3<_> = v0.position.into(); - let pos1: cgmath::Vector3<_> = v1.position.into(); - let pos2: cgmath::Vector3<_> = v2.position.into(); - - let uv0: cgmath::Vector2<_> = v0.tex_coords.into(); - let uv1: cgmath::Vector2<_> = v1.tex_coords.into(); - let uv2: cgmath::Vector2<_> = v2.tex_coords.into(); + let positions: Vec> = + verts.clone().map(|v| v.position.into()).collect::>(); + let uvs: Vec> = + verts.clone().map(|v| v.tex_coords.into()).collect(); // Calculate the edges of the triangle - let delta_pos1 = pos1 - pos0; - let delta_pos2 = pos2 - pos0; - + let delta_pos1 = positions[1] - positions[0]; + let delta_pos2 = positions[2] - positions[0]; // This will give us a direction to calculate the // tangent and bitangent - let delta_uv1 = uv1 - uv0; - let delta_uv2 = uv2 - uv0; + let delta_uv1 = uvs[1] - uvs[0]; + let delta_uv2 = uvs[2] - uvs[0]; // Solving the following system of equations will // give us the tangent and bitangent. @@ -158,24 +152,17 @@ pub async fn load_model( // maps with wgpu texture coordinate system let bitangent = (delta_pos2 * delta_uv1.x - delta_pos1 * delta_uv2.x) * -r; - // We'll use the same tangent/bitangent for each vertex in the triangle - vertices[c[0] as usize].tangent = - (tangent + cgmath::Vector3::from(vertices[c[0] as usize].tangent)).into(); - vertices[c[1] as usize].tangent = - (tangent + cgmath::Vector3::from(vertices[c[1] as usize].tangent)).into(); - vertices[c[2] as usize].tangent = - (tangent + cgmath::Vector3::from(vertices[c[2] as usize].tangent)).into(); - vertices[c[0] as usize].bitangent = - (bitangent + cgmath::Vector3::from(vertices[c[0] as usize].bitangent)).into(); - vertices[c[1] as usize].bitangent = - (bitangent + cgmath::Vector3::from(vertices[c[1] as usize].bitangent)).into(); - vertices[c[2] as usize].bitangent = - (bitangent + cgmath::Vector3::from(vertices[c[2] as usize].bitangent)).into(); - - // Used to average the tangents/bitangents - triangles_included[c[0] as usize] += 1; - triangles_included[c[1] as usize] += 1; - triangles_included[c[2] as usize] += 1; + for i in 0..3 { + // We'll use the same tangent/bitangent for each vertex in the triangle + vertices[c[i] as usize].tangent = + (tangent + cgmath::Vector3::from(vertices[c[i] as usize].tangent)).into(); + vertices[c[1] as usize].bitangent = (bitangent + + cgmath::Vector3::from(vertices[c[1] as usize].bitangent)) + .into(); + + // Used to average the tangents/bitangents + triangles_included[c[i] as usize] += 1; + } } // Average the tangents/bitangents diff --git a/code/intermediate/tutorial13-hdr/src/resources.rs b/code/intermediate/tutorial13-hdr/src/resources.rs index bc6786944..7d0d8f3ea 100644 --- a/code/intermediate/tutorial13-hdr/src/resources.rs +++ b/code/intermediate/tutorial13-hdr/src/resources.rs @@ -125,27 +125,21 @@ pub async fn load_model( // Calculate tangents and bitangets. We're going to // use the triangles, so we need to loop through the // indices in chunks of 3 - for c in indices.chunks(3) { - let v0 = vertices[c[0] as usize]; - let v1 = vertices[c[1] as usize]; - let v2 = vertices[c[2] as usize]; + for c in indices.chunks_exact(3) { + let verts = c.iter().map(|i| vertices[*i as usize]); - let pos0: cgmath::Vector3<_> = v0.position.into(); - let pos1: cgmath::Vector3<_> = v1.position.into(); - let pos2: cgmath::Vector3<_> = v2.position.into(); - - let uv0: cgmath::Vector2<_> = v0.tex_coords.into(); - let uv1: cgmath::Vector2<_> = v1.tex_coords.into(); - let uv2: cgmath::Vector2<_> = v2.tex_coords.into(); + let positions: Vec> = + verts.clone().map(|v| v.position.into()).collect::>(); + let uvs: Vec> = + verts.clone().map(|v| v.tex_coords.into()).collect(); // Calculate the edges of the triangle - let delta_pos1 = pos1 - pos0; - let delta_pos2 = pos2 - pos0; - + let delta_pos1 = positions[1] - positions[0]; + let delta_pos2 = positions[2] - positions[0]; // This will give us a direction to calculate the // tangent and bitangent - let delta_uv1 = uv1 - uv0; - let delta_uv2 = uv2 - uv0; + let delta_uv1 = uvs[1] - uvs[0]; + let delta_uv2 = uvs[2] - uvs[0]; // Solving the following system of equations will // give us the tangent and bitangent. @@ -159,24 +153,17 @@ pub async fn load_model( // maps with wgpu texture coordinate system let bitangent = (delta_pos2 * delta_uv1.x - delta_pos1 * delta_uv2.x) * -r; - // We'll use the same tangent/bitangent for each vertex in the triangle - vertices[c[0] as usize].tangent = - (tangent + cgmath::Vector3::from(vertices[c[0] as usize].tangent)).into(); - vertices[c[1] as usize].tangent = - (tangent + cgmath::Vector3::from(vertices[c[1] as usize].tangent)).into(); - vertices[c[2] as usize].tangent = - (tangent + cgmath::Vector3::from(vertices[c[2] as usize].tangent)).into(); - vertices[c[0] as usize].bitangent = - (bitangent + cgmath::Vector3::from(vertices[c[0] as usize].bitangent)).into(); - vertices[c[1] as usize].bitangent = - (bitangent + cgmath::Vector3::from(vertices[c[1] as usize].bitangent)).into(); - vertices[c[2] as usize].bitangent = - (bitangent + cgmath::Vector3::from(vertices[c[2] as usize].bitangent)).into(); - - // Used to average the tangents/bitangents - triangles_included[c[0] as usize] += 1; - triangles_included[c[1] as usize] += 1; - triangles_included[c[2] as usize] += 1; + for i in 0..3 { + // We'll use the same tangent/bitangent for each vertex in the triangle + vertices[c[i] as usize].tangent = + (tangent + cgmath::Vector3::from(vertices[c[i] as usize].tangent)).into(); + vertices[c[1] as usize].bitangent = (bitangent + + cgmath::Vector3::from(vertices[c[1] as usize].bitangent)) + .into(); + + // Used to average the tangents/bitangents + triangles_included[c[i] as usize] += 1; + } } // Average the tangents/bitangents diff --git a/docs/intermediate/tutorial11-normals/README.md b/docs/intermediate/tutorial11-normals/README.md index 238a76bdb..bff5129a5 100644 --- a/docs/intermediate/tutorial11-normals/README.md +++ b/docs/intermediate/tutorial11-normals/README.md @@ -261,27 +261,21 @@ let meshes = models // Calculate tangents and bitangets. We're going to // use the triangles, so we need to loop through the // indices in chunks of 3 - for c in indices.chunks(3) { - let v0 = vertices[c[0] as usize]; - let v1 = vertices[c[1] as usize]; - let v2 = vertices[c[2] as usize]; + for c in indices.chunks_exact(3) { + let verts = c.iter().map(|i| vertices[*i as usize]); - let pos0: cgmath::Vector3<_> = v0.position.into(); - let pos1: cgmath::Vector3<_> = v1.position.into(); - let pos2: cgmath::Vector3<_> = v2.position.into(); - - let uv0: cgmath::Vector2<_> = v0.tex_coords.into(); - let uv1: cgmath::Vector2<_> = v1.tex_coords.into(); - let uv2: cgmath::Vector2<_> = v2.tex_coords.into(); + let positions: Vec> = + verts.clone().map(|v| v.position.into()).collect::>(); + let uvs: Vec> = + verts.clone().map(|v| v.tex_coords.into()).collect(); // Calculate the edges of the triangle - let delta_pos1 = pos1 - pos0; - let delta_pos2 = pos2 - pos0; - + let delta_pos1 = positions[1] - positions[0]; + let delta_pos2 = positions[2] - positions[0]; // This will give us a direction to calculate the // tangent and bitangent - let delta_uv1 = uv1 - uv0; - let delta_uv2 = uv2 - uv0; + let delta_uv1 = uvs[1] - uvs[0]; + let delta_uv2 = uvs[2] - uvs[0]; // Solving the following system of equations will // give us the tangent and bitangent. @@ -295,24 +289,17 @@ let meshes = models // maps with wgpu texture coordinate system let bitangent = (delta_pos2 * delta_uv1.x - delta_pos1 * delta_uv2.x) * -r; - // We'll use the same tangent/bitangent for each vertex in the triangle - vertices[c[0] as usize].tangent = - (tangent + cgmath::Vector3::from(vertices[c[0] as usize].tangent)).into(); - vertices[c[1] as usize].tangent = - (tangent + cgmath::Vector3::from(vertices[c[1] as usize].tangent)).into(); - vertices[c[2] as usize].tangent = - (tangent + cgmath::Vector3::from(vertices[c[2] as usize].tangent)).into(); - vertices[c[0] as usize].bitangent = - (bitangent + cgmath::Vector3::from(vertices[c[0] as usize].bitangent)).into(); - vertices[c[1] as usize].bitangent = - (bitangent + cgmath::Vector3::from(vertices[c[1] as usize].bitangent)).into(); - vertices[c[2] as usize].bitangent = - (bitangent + cgmath::Vector3::from(vertices[c[2] as usize].bitangent)).into(); - - // Used to average the tangents/bitangents - triangles_included[c[0] as usize] += 1; - triangles_included[c[1] as usize] += 1; - triangles_included[c[2] as usize] += 1; + for i in 0..3 { + // We'll use the same tangent/bitangent for each vertex in the triangle + vertices[c[i] as usize].tangent = + (tangent + cgmath::Vector3::from(vertices[c[i] as usize].tangent)).into(); + vertices[c[1] as usize].bitangent = (bitangent + + cgmath::Vector3::from(vertices[c[1] as usize].bitangent)) + .into(); + + // Used to average the tangents/bitangents + triangles_included[c[i] as usize] += 1; + } } // Average the tangents/bitangents