Practical GPU Graphics with wgpu and Rust
About this Book
wgpu is the next-generation graphics API and future standard in Rust for both native devices and the web, aiming to provide modern 3D graphics and computation capabilities using the GPU acceleration. This book provides all the tools you need to create advanced 3D graphics and GPU computing in Rust using this new wgpu API.
First, this book will take you through the development environment for building wgpu applications in Rust, and then introduce Rust and wgpu basics, shader programs, GPU buffers, and rendering pipelines. Next, you will learn how to create primitives and simple objects in wgpu. As you progress through the chapters, you will get to grips with advanced wgpu topics, including 3D transformations, lighting calculations, colormaps, and textures. At the same time, you will learn how to create advanced 3D wgpu objects, including various 3D wireframes, 3D shapes, and simple and parametric 3D surfaces with colormaps and textures, as well as beautiful 2D and 3D fractal images described by complex functions. In addition, you will explore new wgpu features such as the compute shader and storage buffers, and use them to simulate large particle systems.
By the end of this book, you will have the solid skills you need to build your own GPU-accelerated graphics and computing applications on both native devices and the web in Rust with the wgpu API.
The things you will learn from this book:
- Development environment and tools for creating wgpu apps in Rust.
- Rust and wgpu basics, WGSL shaders, and rendering pipeline.
- Primitives and simple shapes in wgpu.
- 3D transformations, model, viewing, projection, and various coordinate systems.
- GPU buffers, uniform buffer objects, animation, and camera controls.
- Normal vectors, lighting model, ambient, diffuse, and specular light calculations.
- UV coordinates, texture mapping.
- Color model, colormaps, and color interpolation.
- 3D shapes, wireframes, surfaces, and 3D charts.
- 2D and 3D fractal images created in the fragment shader.
- Compute shaders, storage buffers, and large particle system simulation.
Table of Contents
Contents v Introduction 1 Overview 1 What this Book Includes 3 Is this Book for You? 3 What Do You Need to Use this Book? 4 How this Book Is Organized 4 Using Code Examples 6 Customer Support 6 1 Setting Up Development Tools 7 1.1 Hardware Requirements 7 1.2 Install C++ Build Tools 10 1.3 Install Rust 10 1.4 Install Visual Studio Code 11 1.5 Run a Rust Application 11 1.6 Configuration 12 1.7 Creating a Window 15 1.8 Rust Basics 15 1.8.1 Data Types 17 1.8.2 Functions 17 1.8.3 Control Flows 18 1.8.4 Arrays, Vectors, and Slices 21 1.8.5 Structs 22 1.8.6 Enums 23 1.8.7 Generics 24 2 wgpu Basics 25 2.1 First wgpu Example 25 2.1.1 WGSL Shaders 25 2.1.2 Common Rust Code 26 2.1.3 Rust Main Function 28 2.2 wgpu API 30 2.2.1 wgpu Backend 30 2.2.2 Surface 31 2.2.3 Load Shaders 32 2.2.4 Rendering Pipeline 32 2.2.5 Rendering Output 34 2.3 Shader Program 35 2.3.1 Why Use WGSL Shaders? 36 2.3.2 Writing Shader Code 36 2.4 Triangle with Different Vertex Colors 38 2.4.1 Shader Code 39 2.4.2 Rust Code 39 3 wgpu Primitives 41 3.1 Creating Points 42 3.1.1 Rust Code 42 3.1.2 Shader Code 43 3.1.3 Run Application 44 3.2 Creating Lines 45 3.3 Creating Triangles 47 3.3.1 Rust Code 47 3.3.2 Shader Code 48 3.3.3 Run Application 49 4 GPU Buffers 51 4.1 GPU Buffer 51 4.2 Creating a Colored Triangle 52 4.2.1 Rust Code 53 4.2.2 Shader Code 60 4.2.3 Run Application 60 4.3 Creating a Colored Square 61 4.3.1 Rust Code 62 4.3.2 Run Application 62 4.4 Creating a Square with an Index Buffer 63 4.4.1 Rust Code 63 4.4.2 Run Application 65 5 3D Transformations 67 5.1 Basics of 3D Matrices and Transformations 67 5.1.1 Introducing cgmath 67 5.1.2 3D Vector and Matrix Operations 68 5.1.3 Scaling 69 5.1.4 Translation 71 5.1.5 Rotation 72 5.1.6 Combining Transformations 74 5.2 Projections and Viewing 75 5.2.1 Transforming Coordinates 75 5.2.2 Viewing Transform 76 5.2.3 Perspective Projection 79 5.2.4 Orthographic Projection 83 5.3 Transformations in wgpu 86 6 3D Shapes and Camera 87 6.1 Uniform Buffers and Bind Groups 87 6.2 Creating a 3D Line 89 6.2.1 Common Code 89 6.2.2 Rust Code 92 6.2.3 Shader Program 98 6.2.4 Run Application 98 6.3 Creating a Cube with Distinct Face Colors 100 6.3.1 Create Vertex Data 100 6.3.2 Rust Code 102 6.3.3 Shader Program 109 6.3.4 Run Application 110 6.4 Creating a Cube with Distinct Vertex Colors 111 6.4.1 Create Vertex Data 111 6.4.2 Rust Code 111 6.4.3 Run Application 118 6.5 Rotating Objects 119 6.5.1 Rust Code 119 6.5.2 Run Application 120 6.6 Camera Controls 121 6.6.1 Camera Code 121 6.6.2 Rust Code 123 6.6.3 Run Application 130 7 3D Wireframe Shapes 131 7.1 Common Code 131 7.2 Cube Wireframe 136 7.2.1 Rust File 136 7.2.2 Run Application 137 7.3 Sphere Wireframe 138 7.3.1 Spherical Coordinate System 138 7.3.2 Rust Code 140 7.3.3 Run Application 141 7.4 Cylinder Wireframe 141 7.4.1 Cylindrical Coordinate System 142 7.4.2 Rust Code 143 7.4.3 Run Application 145 7.5 Cone Wireframe 146 7.5.1 Rust Code 147 7.5.2 Run Application 148 7.6 Torus Wireframe 149 7.6.1 Rust Code 150 7.6.2 Run Application 151 8 Lighting in WGPU 153 8.1 Light Components 153 8.2 Normal Vectors 154 8.2.1 Surface Normal of a Cube 155 8.2.2 Surface Normal of a Sphere 155 8.2.3 Surface Normal of a Cylinder 155 8.2.4 Surface Normal of a Polyhedral Surface 155 8.3 Lighting Calculation 156 8.3.1 Diffuse Light 156 8.3.2 Specular Light 157 8.4 Lighting in Shaders 158 8.4.1 Transform Normals 158 8.4.2 Shader with Lighting 159 8.5 Common Code 161 8.6 Cube with Lighting 170 8.6.1 Rust Code 170 8.6.2 Run Application 171 8.7 Sphere with Lighting 171 8.7.1 Vertex and Normal Data 172 8.7.2 Rust Code 173 8.7.3 Run Application 174 8.8 Cylinder with Lighting 174 8.8.1 Vertex and Normal Data 175 8.8.2 Rust Code 177 8.8.3 Run Application 177 8.9 Cone with Lighting 178 8.9.1 Vertex and Normal Data 179 8.9.2 Rust Code 180 8.9.3 Run Application 181 8.10 Torus with Lighting 181 8.10.1 Vertex and Normal Data 182 8.10.2 Rust Code 183 8.10.3 Run Application 183 9 Colormaps and 3D Surfaces 185 9.1 Color Models 185 9.2 Colormaps 186 9.2.1 Colormap Data 186 9.2.2 Color Interpolation 187 9.3 Shaders with Lighting and Vertex Color 188 9.4 Simple 3D Surfaces 190 9.4.1 Position, Normal, and Color Data 191 9.4.2 Common Code 193 9.4.3 Sinc Surface 201 9.4.4 Peaks Surface 203 9.5 Parametric 3D Surfaces 205 9.5.1 Vertex and Normal Data 205 9.5.2 Klein Bottle 206 9.5.3 Wellenkugel Surface 209 9.5.4 Seashell Surface 210 9.5.5 Sievert-Enneper Surface 212 9.5.6 Breather Surface 213 10 Textures 217 10.1 Texture Coordinates 217 10.2 Texture Mapping in WGPU 218 10.3 Shaders with Texture 222 10.4 Common Code 223 10.5 Simple 3D Shapes 232 10.5.1 Cube with Texture 232 10.5.2 Sphere with Texture 235 10.5.3 Cylinder with Texture 237 10.6 Simple 3D Surfaces 241 10.6.1 Sinc Surface with Texture 243 10.6.2 Peaks Surface with Texture 245 10.7 Parametric 3D Surfaces 246 10.7.1 Klein Bottle with Texture 248 10.7.2 Wellenkugel Surface with Texture 250 10.8 Multiple Textures 252 10.8.1 Texture Coordinates 252 10.8.2 Rust Code 254 10.8.3 Run Application 254 11 3D Surface Charts 257 11.1 Wireframe as Texture 258 11.1.1 Square Textures 258 11.1.2 Texture Coordinates 259 11.2 Shaders for 3D Charts 259 11.3 Common Code 261 11.4 Simple 3D Surface Charts 269 11.4.1 Sinc Surface Chart 271 11.4.2 Peaks Surface Chart 274 11.5 Parametric 3D Surface Charts 275 11.5.1 Sphere Surface Chart 277 11.5.2 Torus Surface Chart 278 11.5.3 Klein Bottle Surface Chart 280 11.5.4 Wellenkugel Surface Chart 282 12 Creating Multiple Objects 285 12.1 Creating Two Cubes 285 12.1.1 Rust Code 285 12.1.2 Run Application 292 12.2 Creating Multiple Cubes with Instancing 292 12.2.1 Rust Code 293 12.2.2 Shader Code 300 12.2.3 Run Application 300 12.3 Creating Different Objects 301 12.3.1 Rust Code 301 12.3.2 Run Application 303 12.4 Creating Objects Using Multiple Pipelines 304 12.4.1 Rust Code 304 12.4.2 Run Application 315 12.5 Creating 3D Charts with Multiple Pipelines 315 12.5.1 Create Wireframe Data 316 12.5.2 Modify Shader Program 317 12.5.3 Rust Code 318 12.5.4 Run Application 327 12.6 Charts with Coordinate Axes 329 12.6.1 Shaders for Coordinate Axes 329 12.6.2 Rust Code 330 12.6.3 Run Application 333 12.7 Creating 3D Charts with Multiple Render Passes 334 12.7.1 Rust Code 334 12.7.2 Run Application 337 13 Compute Shaders and Particles 339 13.1 Compute Shader 339 13.1.1 Compute Space and Workgroups 340 13.1.2 Write and Read Buffer 341 13.2 2D Rotation in GPU 343 13.2.1 Rust Code 343 13.2.2 Shader Code 346 13.2.3 Run Application 347 13.3 Compute Boids 347 13.3.1 Rust Code 347 13.3.2 Shader Code 354 13.3.3 Run Application 356 13.4 Particles under Gravity 358 13.4.1 Rust Code 358 13.4.2 Shader Code 366 13.4.3 Run Application 368 13.5 Particle Collision 370 13.5.1 Rust Code 370 13.5.2 Shader Code 378 13.5.3 Run Application 380 14 Visualizing Complex Functions 383 14.1 Complex Functions in Shader 383 14.1.1 Math Operations 384 14.1.2 Commonly Used Functions 384 14.2 Color Functions 386 14.2.1 Color Conversion in Shader 387 14.2.2 Colormaps in Shader 388 14.3 Domain Coloring for Complex Functions 392 14.3.1 Rust Code 392 14.3.2 Shader Code 397 14.3.3 Complex function with id = 0 399 14.3.4 Complex Function with id = 1 400 14.3.5 Complex Function with id = 2 401 14.3.6 Complex Function with id = 3 402 14.3.7 Complex Function with id = 4 402 14.3.8 Complex Function with id = 5 403 14.3.9 Complex Function with id = 6 404 14.3.10 Complex Function with id = 7 404 14.3.11 Complex Function with id = 8 405 14.3.12 Complex Function with id = 9 406 14.3.13 Complex Function with id = 10 406 14.4 Domain Coloring for Iterated Functions 407 14.4.1 Shader Code 407 14.4.2 Iterated Function with id = 0 410 14.4.3 Iterated Function with id = 1 410 14.4.4 Iterated Function with id = 2 411 14.4.5 Iterated Function with id = 3 412 14.4.6 Iterated Function with id = 4 412 14.4.7 Iterated Function with id = 5 413 14.4.8 Iterated Function with id = 6 414 14.4.9 Iterated Function with id = 7 414 14.4.10 Iterated Function with id = 8 415 14.4.11 Iterated Function with id = 9 416 14.4.12 Iterated Function with id = 10 416 14.5 Fractal: Mandelbrot Set 417 14.5.1 Mandelbrot Set Formula 417 14.5.2 Rust Code 418 14.5.3 Shader Code 422 14.5.4 Run Application 424 14.6 Fractal: Julia Set 424 14.6.1 Rust Code 424 14.6.2 Shader Code 429 14.6.3 Run Application 431 14.7 3D Fractals 432 14.7.1 Common Code 432 14.7.2 Mandelbulb 437 14.7.3 Mandelbrot in 3D Space 441 14.7.4 Mandelbox Sweeper 445 Index 451
What This Book Includes
Is This Book for You
What Do You Need to Use This Book
How This Book is Organized
Using Code Examples
Welcome to Practical GPU Graphics with wgpu and Rust. The wgpu API is based on the WebGPU standard and is a Rust implementation of the WebGPU API specifications. WebGPU is the next-generation graphics API for the web, which is being developed by the W3C GPU for the Web Community Group with engineers from Apple, Google, Microsoft, Mozilla, and others. It is a future web standard for graphics and compute, aiming to provide modern 3D graphics and computation capabilities with GPU acceleration on the web.
The wgpu API is a cross-platform, safe, pure-Rust graphics API. Even though it is based on the WebGPU standard, it can run not only on the web via WebAssembly, but also natively on Vulkan, Metal, DirectX12, DirectX11, and OpenGLES. This book will provide all the tools you need to help you create advanced 3D graphics and GPU computing in Rust on native devices using this new graphics API. I hope that this book will be useful for web developers, graphics creators, computer graphics programmers, game developers, and students of all skill levels who are interested in graphics development on the web and on devices with native modern graphics APIs.
Unlike WebGL which is based on OpenGL, WebGPU and wgpu are not direct ports of any existing native APIs. They are based on concepts in the Vulkan, Metal, and Direct3D12 APIs and are intended to provide high performance on these modern native graphics APIs across mobile and desktop platforms.
In order to understand wgpu technology, we need to review a brief history of native graphics technologies. The first to come was OpenGL, originally developed in the early 1990s. It is a low-level high performance graphics technology, which WebGL is based on. Since its inception, many graphics applications based on OpenGL have been developed. Modern GPUs actually work very differently from how the original OpenGL did – but many of the core concepts of OpenGL remain the same.
As GPUs became more complex and powerful, the graphics driver ended up having to do a lot of extremely complex work. This made graphics drivers notoriously buggy, and in many cases slower, too, as they had to do all the work on the fly. To improve OpenGL’s performance, Khronos, the group behind OpenGL, proposed a new, completely redesigned modern graphics API called Vulkan, which was released in 2016. Vulkan is even more low-level, faster, and simpler, and is a much better match for modern hardware.
However, using Vulkan also meant that applications had to completely rewrite all their graphics code in order to support it. This kind of tectonic shift in technology takes years to play out, and as a result, there is still a lot of OpenGL out there.
While Vulkan was designed to be a standard API able to work on all systems, as has long been the case with standards, Apple also came up with Metal for iOS and MacOS, while Microsoft came up with DirectX12 for Windows and Xbox. Both are more or less the same idea as Vulkan: new, lower-level APIs that throw out all the historical baggage and start with a clean slate design that much more closely matches how modern GPU hardware works.
With the graphics community moving on to this new generation of APIs, the question then became what to do with the web. WebGL is essentially OpenGL with many of the same pitfalls, while high-performance web game engines still stand to greatly benefit from the new generation of graphics APIs.
Unfortunately, unlike OpenGL, Vulkan has run into trouble achieving true cross-platform reach thanks to Apple. MacOS and iOS only support Metal and have no official support for Vulkan, although there are third-party libraries for it. Furthermore, Vulkan itself is still not very suitable for the web – it is just too low-level, even dealing with minutiae like GPU memory allocators so that AAA game engines can extract the maximum conceivable performance. This is overkill for web platforms, plus security is a much more significant concern in browsers.
So the solution was an all-new API design, high-level enough to be usable and secure in a browser, and able to be implemented on top of any one of Vulkan, Metal and DirectX12. This is WebGPU, which looks like the only truly cross-platform, modern, and low-level graphics API for web applications.
Based on the WebGPU standard, the wgpu API is a native WebGPU implementation in Rust. It can run natively on cross-platform devices with any modern graphics API such as Vulkan, Metal, or DirectX12. It can also run on the web by converting wgpu apps into WebAssembly packages.
Note that WebGPU and wgpu have not been finalized and are still in the early stages of development, so their API interfaces may change frequently before they are officially released. In addition, WebGPU and wgpu use a new shader language called WGSL (WebGPU Shading Language) instead of the traditional GLSL shader language used in OpenGL and WebGL applications.
Practical GPU Graphics with wgpu and Rust provides everything you need to create advanced 3D graphics objects in your wgpu applications using GPU acceleration. In this book, you will learn how to create a variety of 3D graphics and charts that range from simple 3D shapes such as cubes, spheres, cylinders, to complex 3D surface graphics such as 3D wireframes, 3D surface charts, and complex particle systems created using compute shaders. I will try my best to introduce readers to the wgpu API, the next-generation graphics API for native graphics devices, in a simple way – simple enough to be easily followed by programmers who have little experience in developing advanced graphics applications. You can learn from this book how to create a full range of 3D graphics applications using the wgpu API and WGSL shader program.
In fact, there are several bindings of the wgpu-native API in different programming languages, including C, Python, C# .NET, Java, and Julia, to name a few. Here, I use the Rust wrapper – wgpu, because of Rust’s performance and safety features. Rust is a low-level, statically typed, system-programming language, which solves problems that C and C++ have been struggling with for a long time, such as errors and building concurrent programs. Compared to C and C++, Rust has three main benefits: better memory safety due to its compiler, easier concurrency due to a data ownership model that prevents data races, and zero-cost abstraction. According to a recent Stack-Overflow survey, Rust has been the most loved programming language for the last five years in a row (https://insights.stackoverflow.com/survey /2020#technology).
What This Book Includes
This book and its sample code listings, which are available for download at my website at https://drxudotnet.com, provide you with
- A complete, in-depth instruction to practical 3D graphics programming in Rust with wgpu. After reading this book and running the example programs, you will be able to create various sophisticated 3D graphics and charts with GPU acceleration in your native applications.
- Over 50 ready-to-run example projects that allow you to explore the 3D graphics techniques described in this book. You can use these examples to get a better understanding of how 3D graphics and charts are created using the wgpu API and shader program. You can also modify the programs or add new features to them to form the basis of your own projects. Some of the example code listings provided with this book are already sophisticated chart and graphics projects, and can be directly used in your own real-world applications.
- • Many functions and components in the sample code listings that you will find useful in your 3D graphics development. These functions and components include 3D transformation, projection, colormaps, lighting models created in fragment shaders, wgpu pipeline settings, WGSL shader code, and many other useful utility functions. You can extract these functions and components and plug them into your own applications.
Is This Book for You
Throughout the book, I will emphasize the usefulness of wgpu graphics programming to real-world applications. If you follow the instructions presented in this book closely, you will easily be able to develop various graphics and chart applications with GPU acceleration from simple 3D shapes to 3D surfaces with powerful colormap, wireframe, and texture mapping. You can also use the compute and fragment shaders to create complicated particle systems, domain coloring for complex functions, and fractal images. At the same time, I will not spend too much time discussing program style and code optimization because there is a plethora of books out there already dealing with those topics. Most of the example programs you will find in this book omit error handlings, which makes the code easier to understand by focusing only on the key concepts and practical applications.
What Do You Need to Use This Book
You will need no special equipment to make the best use of this book and understand its algorithms. This book takes full advantage of open source frameworks and libraries. The sample programs companying this book can run on various operating systems, including Windows, Linux, iOS, and MacOS. This book uses Visual Studio Code (VS Code), Rust, and Cargo package manager for its development environment and tools. VS Code is a lightweight IDE and powerful source code editor that runs on various operating systems. It has support for Rust and WGSL with the help of relevant extensions.
Since the wgpu standard has not been finalized and is still in early development stage, its API may change frequently. This book uses the wgpu crate version 0.11 for implementing wgpu applications.
If you install other versions of the wgpu API, you may still be able to run most of the sample code with few modifications. Please remember, however, that this book is intended for that specific version of the wgpu API, on which all of the example programs were created and tested, so it is best to run the sample code in the same development environment and using the same version of the wgpu API..
In addition, your operating system needs to have a modern GPU as well as the DirectX 12, Metal, or Vulkan API support on your graphics card.
How This Book Is Organized
This book is organized into fourteen chapters, each of which covers a different topic about modern wgpu graphics programming. The following summaries of each chapter should give you an overview of the book’s content:
Chapter 1, Set Up Development Tools
This chapter explains how to set up the packages and tools required for wgpu application development. VS Code, Rust, and Cargo package manager will be used as our development environment and tools. It also provides a brief introduction to Rust programming.
Chapter 2, WGPU Basics
This chapter provides a brief overview on the current wgpu technology, and then uses a simple triangle example to explain key aspects of the wgpu API, including wgpu context, the rendering pipeline, the shader program, and rendering graphics on a window surface.
Chapter 3, WGPU Primitives
This chapter demonstrates how to draw basic shapes in wgpu, including points, lines, and triangles. These basic shapes are referred to as primitives. There is no built-in support for curves or curved surfaces; they must be approximated by primitives. Currently, wgpu includes five primitives.
Chapter 4, GPU Buffers
This chapter introduces GPU buffers that hold vertex data and color information, and explains how to use GPU buffers to create colorful triangle and square with each vertex having a distinct color.
Chapter 5, 3D Transformations
This chapter explains how to perform basic 3D transformations, including translation, scaling, and rotation. It also describes how to construct various matrix representations used in 3D graphics, including model matrix, viewing matrix, and projection matrix. These matrices will be used to display 3D graphics objects on a 2D screen.
Chapter 6, 3D Shapes and Camera
This chapter shows how to use transformation, viewing, projection matrices, and the camera to create real-world 3D shapes – a 3D line and two cubes: one with distinct face colors and the other with distinct vertex colors. In doing so, you will learn two important concepts in wgpu: bind groups and uniform buffer objects.
Chapter 7, 3D Wireframe Shapes
A wireframe model is a visual representation of 3D objects used in computer graphics. It is created by drawing just the outlines of the polygons that make up the object. This chapter explains how to create wireframe models in wgpu for various 3D shapes, including cube, sphere, cylinder, cone, and torus. The key to create 3D wireframe shapes is to specify correct coordinates for their vertices.
Chapter 8, Lighting in WebGPU
This chapter demonstrates how to build a simple lighting model in wgpu and how to use it to simulate light sources and the way that the light that they emit interacts with your objects on the scene. Here, I will discuss three light sources: ambient light, diffuse light, and specular light.
Chapter 9, Colormaps and 3D surfaces
This chapter explains how to use the color model and colormap to render the simple and parametric 3D surfaces by specifying various mathematical functions. Surfaces play an important role in various applications, including computer graphics, virtual reality, computer games, and 3D data visualization.
Chapter 10, Textures
This chapter discusses 2D image textures that can be applied to a surface to make the color of the surface vary from point to point, something like painting a copy of the image onto the surface. It shows how to map 2D textures onto various surfaces in wgpu.
Chapter 11, 3D Surface Charts
Surface charts are plots of 3D data. Rather than displaying the individual data points, surface charts show a functional relationship between a dependent variable y, and two independent variables x and z. This chapter explains how to create real-word 3D surface charts with colormaps, and how to add wireframe to the surface charts by mapping transparent square images onto the surface.
Chapter 12, Creating Multiple Objects
This chapter explains several approaches used to create multiple objects in a scene. One approach is to use uniform transformations or instancing to render the same object multiple times. Another approach is to combine the vertex data of different objects together and render them as a single object. The third approach is to use different pipelines or different render passes to render different objects.
Chapter 13, Compute Shaders and Particles
This chapter introduces the compute shader and describes how to use it in a simple 2D rotation example. It then applies the compute shader to particle systems – one system mimics the flocking behavior of birds, another simulates the effect of gravity on particles, and the third one models particle kinematics.
Chapter 14, Visualizing Complex Functions
This chapter illustrates how to generate domain coloring in wgpu for various complex functions. It also explains how to create fractal images for the Mandelbrot and Julia sets, as well as some 3D fractal shapes by writing the computation-intensive code directly in the fragment shaders.
Using Code Examples
You may use the code in this book in your own applications and documentation. You do not need to contact the author or the publisher for permission unless you are reproducing a significant portion of the code. For example, writing a program that uses several chunks of code from this book does not require permission. Selling or distributing the example code listings does require permission. Incorporating a significant amount of example code from this book into your applications and documentation also requires permission. Integrating the example code from this book into commercial products is not allowed without written permission of the author.