From 27fb79c4ab5e6b205c56b4ba0768aabd6cf076f0 Mon Sep 17 00:00:00 2001 From: Ben Hansen Date: Thu, 14 Apr 2022 14:50:57 -0600 Subject: [PATCH] fixes #337 --- docs/intermediate/tutorial10-lighting/README.md | 16 ++++++++++++++++ .../tutorial10-lighting/normal-scale-issue.png | Bin 0 -> 13226 bytes 2 files changed, 16 insertions(+) create mode 100644 docs/intermediate/tutorial10-lighting/normal-scale-issue.png diff --git a/docs/intermediate/tutorial10-lighting/README.md b/docs/intermediate/tutorial10-lighting/README.md index 69671951..d204c5bb 100644 --- a/docs/intermediate/tutorial10-lighting/README.md +++ b/docs/intermediate/tutorial10-lighting/README.md @@ -795,6 +795,22 @@ Bringing back our other objects, and adding the ambient lighting gives us this. ![./ambient_diffuse_lighting.png](./ambient_diffuse_lighting.png); +
+ +If you can guarantee that your model matrix will always apply uniform scaling to your objects, you can get away with just using the model matrix. Github user @julhe pointed shared this code with me that does the trick: + +```wgsl +out.world_normal = (model_matrix * vec4(model.normal, 0.0)).xyz; +``` + +This works by exploiting the fact that multiplying a 4x4 matrix by a vector with 0 in the w component, only the rotation and scaling will be applied to the vector. You'll need to normalize this vector though as normals need to be unit length for the calculations to work. + +The scaling factor *needs* to be uniform in order for this to work. If it's not the resulting normal will be skewed as you can see in the following image. + +![./normal-scale-issue.png](./normal-scale-issue.png) + +
+ ## Specular Lighting Specular lighting describes the highlights that appear on objects when viewed from certain angles. If you've ever looked at a car, it's the super bright parts. Basically, some of the light can reflect of the surface like a mirror. The location of the hightlight shifts depending on what angle you view it at. diff --git a/docs/intermediate/tutorial10-lighting/normal-scale-issue.png b/docs/intermediate/tutorial10-lighting/normal-scale-issue.png new file mode 100644 index 0000000000000000000000000000000000000000..fa17d855419b17a42b75ea6ed77883d411c9f654 GIT binary patch literal 13226 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 eXWgDcL9yKS?&KZ<_rPUHkjhI