You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
</pre></code><divclass="code-fragments-caption"><atarget="_blank" href="https://shi-yan.github.io/WebGPUUnleashed/code/code.html?highlight=37:68#5_02_toon_shading">5_02_toon_shading/index.html:37-68 Outline Shader</a></div></div><p>The above shader does the inflation in the clip space. The two parameters passed into the vertex shader are the vertex position in 3D and the vertex's normal in 3D. We convert the position to the clip space position as always. For the normal vector, we apply the normal matrix and then projection. notice that the w component is set to 0.0 because it is a vector.</p><p>after that, we need to inflate the clip space position. again, since the silhouette is in 2D, we don't want to touch the zw components, we leave them as they are. for the xy axis, we offset them by normalize(clip_normal.xy)*6.4/screenDim * out.clip_position.w. here, dividing the clip space normal by the screen dimension is to compensate for the screen size and aspect ratio. We want the silhouette width to be uniform regardless of the screen size and aspect ratio. timing it by out.clip_position is because the graphics pipeline will later divide the clip space position by the w component when converting it to the normalized device coordinates. to avoid further change to the silhouette thickness during this conversion, we premultiply it by the w.</p><p>the fragment shader is simple. we simply output pure black pixels. not let's examine the javascript code:</p><divclass="code-fragments"><pre><codeclass="language-javascript code-block" startNumber=253>let { positionBuffer, normalBuffer, indexBuffer, indexSize } = await loadObj(device, '../data/teapot.obj');
191
+
</pre></code><divclass="code-fragments-caption"><atarget="_blank" href="https://shi-yan.github.io/WebGPUUnleashed/code/code.html?highlight=36:67#5_02_toon_shading">5_02_toon_shading/index.html:37-68 Outline Shader</a></div></div><p>The above shader does the inflation in the clip space. The two parameters passed into the vertex shader are the vertex position in 3D and the vertex's normal in 3D. We convert the position to the clip space position as always. For the normal vector, we apply the normal matrix and then projection. notice that the w component is set to 0.0 because it is a vector.</p><p>after that, we need to inflate the clip space position. again, since the silhouette is in 2D, we don't want to touch the zw components, we leave them as they are. for the xy axis, we offset them by normalize(clip_normal.xy)*6.4/screenDim * out.clip_position.w. here, dividing the clip space normal by the screen dimension is to compensate for the screen size and aspect ratio. We want the silhouette width to be uniform regardless of the screen size and aspect ratio. timing it by out.clip_position is because the graphics pipeline will later divide the clip space position by the w component when converting it to the normalized device coordinates. to avoid further change to the silhouette thickness during this conversion, we premultiply it by the w.</p><p>the fragment shader is simple. we simply output pure black pixels. not let's examine the javascript code:</p><divclass="code-fragments"><pre><codeclass="language-javascript code-block" startNumber=253>let { positionBuffer, normalBuffer, indexBuffer, indexSize } = await loadObj(device, '../data/teapot.obj');
192
192
this.positionBuffer = positionBuffer;
193
193
// The normal buffer contains vertex normals calculated as averages of adjacent surface normals.
194
194
this.normalBuffer = normalBuffer;
@@ -217,15 +217,15 @@ <h2 >5.2 Toon Shading</h2><p>achieving realistisity is not the only goal of rend
217
217
format: 'depth32float'
218
218
}
219
219
}
220
-
</pre></code><divclass="code-fragments-caption"><atarget="_blank" href="https://shi-yan.github.io/WebGPUUnleashed/code/code.html?highlight=253:258,634:656#5_02_toon_shading">5_02_toon_shading/index.html:253-656 Outline Pipeline Setup</a></div></div><p>when we load the obj file, we have already established the normal buffer containing the vertex normals calculated as an average of adjacent surface normals. When setting up the pipeline for rendering the outline, we set the cullMode to front to peal the front side of the inflated object. Also, notice that we enable the depth testing here.</p><p>in the second part of this tutorial, we will look at how to achieve the painterly shading effect. painterly styles don't usually have smooth color transition as we see on a physically accurate picture. the color transition is often discretized. also the color use is also false colors that can't be described by lighting equations attempt to achieve physical accuracy.</p><p>but it is not difficult to achieve this discretized false color effect. all we need to do is introducing another layer of indirection by using a look up table. We will still using the same phong shading algorithm to calculate lighting as before. The difference is, before, we directly calculate the final color. this time, we only calculate a light intensity as a single value. then, we use a prebuild lookup table to transfer the intensity into colors. our lookup table is in 1D, and is able to convert a value in the range [0,1] into an arbitrary RGB color. in our setup, our 1D texture contains a few bands of false colors, our final image will be rendered using these false colors.</p><p>let's look at the shader first. Again, this shader is modified from the shadow map shader.</p><divclass="code-fragments"><pre><codeclass="language-javascript code-block" startNumber=86>// Instead of setting colors as RGB, we use scalars here as we only want to calculate intensity.
220
+
</pre></code><divclass="code-fragments-caption"><atarget="_blank" href="https://shi-yan.github.io/WebGPUUnleashed/code/code.html?highlight=252:257,633:655#5_02_toon_shading">5_02_toon_shading/index.html:253-656 Outline Pipeline Setup</a></div></div><p>when we load the obj file, we have already established the normal buffer containing the vertex normals calculated as an average of adjacent surface normals. When setting up the pipeline for rendering the outline, we set the cullMode to front to peal the front side of the inflated object. Also, notice that we enable the depth testing here.</p><p>in the second part of this tutorial, we will look at how to achieve the painterly shading effect. painterly styles don't usually have smooth color transition as we see on a physically accurate picture. the color transition is often discretized. also the color use is also false colors that can't be described by lighting equations attempt to achieve physical accuracy.</p><p>but it is not difficult to achieve this discretized false color effect. all we need to do is introducing another layer of indirection by using a look up table. We will still using the same phong shading algorithm to calculate lighting as before. The difference is, before, we directly calculate the final color. this time, we only calculate a light intensity as a single value. then, we use a prebuild lookup table to transfer the intensity into colors. our lookup table is in 1D, and is able to convert a value in the range [0,1] into an arbitrary RGB color. in our setup, our 1D texture contains a few bands of false colors, our final image will be rendered using these false colors.</p><p>let's look at the shader first. Again, this shader is modified from the shadow map shader.</p><divclass="code-fragments"><pre><codeclass="language-javascript code-block" startNumber=86>// Instead of setting colors as RGB, we use scalars here as we only want to calculate intensity.
221
221
const diffuseConstant:f32 = 1.0;
222
222
const specularConstant:f32 = 0.0;
223
223
const ambientConstant:f32 = 0.0;
224
224
</pre></code><divclass="code-fragments-separator">• • •</div><pre><codeclass="language-javascript code-block" startNumber=168>// We apply the same Phong shading, but instead of deriving the final color, we obtain an intensity.
225
225
var intensity:f32 = max(dot(-lightDir, n), 0.0)* diffuseConstant + specular(-lightDir, viewDir, n, shininess) * specularConstant;
226
226
// With the light intensity, we look up the final color.
227
227
var diffuse:vec3<f32> = textureSample(t_shade, s_shade, intensity * visibility).xyz;
228
-
</pre></code><divclass="code-fragments-caption"><atarget="_blank" href="https://shi-yan.github.io/WebGPUUnleashed/code/code.html?highlight=86:89,168:171#5_02_toon_shading">5_02_toon_shading/index.html:86-171 Painterly Shader</a></div></div><p>And finally, let's see, on the javascript side, how this 1D lookup texture is set up.</p><divclass="code-fragments"><pre><codeclass="language-javascript code-block" startNumber=260>// 1D texture, width is hardcoded to 128.
228
+
</pre></code><divclass="code-fragments-caption"><atarget="_blank" href="https://shi-yan.github.io/WebGPUUnleashed/code/code.html?highlight=85:88,167:170#5_02_toon_shading">5_02_toon_shading/index.html:86-171 Painterly Shader</a></div></div><p>And finally, let's see, on the javascript side, how this 1D lookup texture is set up.</p><divclass="code-fragments"><pre><codeclass="language-javascript code-block" startNumber=260>// 1D texture, width is hardcoded to 128.
229
229
const shadeTextureDesc = {
230
230
size: [128],
231
231
dimension: '1d',
@@ -269,7 +269,7 @@ <h2 >5.2 Toon Shading</h2><p>achieving realistisity is not the only goal of rend
269
269
}, { width: 128 });
270
270
// Wait for completion.
271
271
await device.queue.onSubmittedWorkDone();
272
-
</pre></code><divclass="code-fragments-caption"><atarget="_blank" href="https://shi-yan.github.io/WebGPUUnleashed/code/code.html?highlight=260:303#5_02_toon_shading">5_02_toon_shading/index.html:260-303 Setup 1D Lookup Texture</a></div></div><p>Together with the outline shader, we now have the toon shading effect:</p><p><divclass="img-container"><imgclass="img" onclick="openImage(this)" src="placeholder.jpg" alt="Image to Show the Result" sources='[]' /><divclass="img-title">Image to Show the Result</div></div></p>
272
+
</pre></code><divclass="code-fragments-caption"><atarget="_blank" href="https://shi-yan.github.io/WebGPUUnleashed/code/code.html?highlight=259:302#5_02_toon_shading">5_02_toon_shading/index.html:260-303 Setup 1D Lookup Texture</a></div></div><p>Together with the outline shader, we now have the toon shading effect:</p><p><divclass="img-container"><imgclass="img" onclick="openImage(this)" src="placeholder.jpg" alt="Image to Show the Result" sources='[]' /><divclass="img-title">Image to Show the Result</div></div></p>
0 commit comments