Chapters

Hide chapters

Metal by Tutorials

Fifth Edition · macOS 26, iOS 26 · Swift 6, Metal 3 · Xcode 26

Section I: Beginning Metal

Section 1: 10 chapters
Show chapters Hide chapters

Section II: Intermediate Metal

Section 2: 8 chapters
Show chapters Hide chapters

Section III: Advanced Metal

Section 3: 8 chapters
Show chapters Hide chapters

22. Reflection & Refraction
Written by Marius Horga & Caroline Begbie

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

When you create your game environments, you may need lakes of shimmering water or crystal balls. To look realistic, shiny glass objects require both reflection and refraction.

Reflection is one of the most common interactions between light and objects. Imagine looking into a mirror. Not only would you see your image being reflected, but you’d also see the reflection of any nearby objects.

Refraction is another common interaction between light and objects that you often see in nature. While it’s true that most objects in nature are opaque — thus absorbing most of the light they get — the few objects that are translucent, or transparent, allow for the light to propagate through them.

Reflection and refraction
Reflection and refraction

As with all realistic physical phenomena, it is difficult to approximate nature in real time. We’re rapidly approaching higher GPU efficiency where ray tracing algorithms may be viable in games, but for a quick and easy solution, rasterized reflection and refraction is the way to go.

An exemplary algorithm for creating realistic water was developed by Michael Horsch in 2005. This realistic water algorithm is purely based on lighting and its optical properties, as opposed to having a water simulation based on physics.

The Starter Project

➤ In Xcode, open the starter project for this chapter.

The starter project is similar to the project at the end of the previous chapter, with a few additions that include:

  • GameScene.swift contains a new scene with new models and renders a new skybox texture. You can move around the scene using WASD keys, and look about using the mouse or trackpad. Scrolling the mouse wheel, or pinching on iOS, moves you up and down, so you can get better views of your lake. The number 1 key will position the camera looking down on the scene, and number 2 will return the camera to its original position.
  • WaterRenderPass.swift, in the Render Passes folder, contains a new render pass. It’s similar to ForwardRenderPass, but refactors the command encoder setup into a new render method. WaterRenderPass is all set up and ready to render in Renderer, but it will do nothing until you assign it a render pass descriptor.
  • Water.swift, in the Geometry folder, contains a new Water class, similar to Model. The class loads a primitive mesh plane and is set up to render the plane with its own pipeline state.
  • Pipelines.swift has new pipeline state creation methods to render water and a terrain.

➤ Build and run the app.

The starter app
The starter app

Visitors to this quaint cottage would love a recreational lake for swimming and fishing.

Terrains

Many game scenes will have a ground terrain, or landscape, and this terrain may need its own shader. The starter project includes Terrain.swift, which contains Terrain, a subclass of Model. Changing shaders entails loading a new pipeline state, so Terrain creates its own pipeline state object along with a texture for use later.

Rendering Rippling Water

Now that you’re acquainted with the code, here’s the plan on how you’ll proceed through the chapter:

1. Creating the Water Surface

➤ In the Geometry folder, open Water.swift, and examine the code.

Creating the Water Shaders

➤ In the Shaders folder, create a new Metal file named Water.metal, and add this:

Adding the Water to Your Scene

➤ Open GameScene.swift, and add a new property:

Gda imanaod dukij qwedo
Hci unuyuop yelur qtune

2. Rendering the Reflection

The water plane should reflect its surroundings. In Chapter 21, “Image-Based Lighting”, you reflected the skybox onto objects, but this time you’re also going to reflect the house and terrain on the water.

Iboziox mayjenreof
Avecion lirfayciuw

Axqunlucy fuchimveor
Ikkoqmezw vaywugveeg

Ritxikhac waredo rifoteuf
Gazqazfan mazoro gupazaan

3. Creating Clipping Planes

A clipping plane, as its name suggests, clips the scene using a plane. It’s hardware accelerated, meaning that if geometry is not within the clip range, the GPU immediately discards the vertex and doesn’t put it through the entire pipeline. You may get a significant performance boost as some of the geometry will not need to get processed by the fragment shaders anymore.

Dlo rlamhajv mpagi
Jfo mveqfucm lriji

Xecwejokj imovu wna jveqvunk sveba
Xahxicuxp utixo wpa ppuyxiww mvado

Codciytuwn qja qfz sikgubpgd
Vemzuzfurx rwu pdb mivyaczyv

4. Rippling Normal Maps

➤ Open Textures.xcassets, and select normal-water. This is a normal map that you’ll use for the water ripples.

Jgu bocir foglqu rulyuc fuz
Jpu qudap gabqve zigpos zij

Nicfufw yiroy nufdtil
Zalqacr buquq fazhyiy

5. Adding Refraction

Implementing refraction is very similar to reflection, except that you only need to preserve the part of the scene below the clipping plane.

Lalqelegz yabef sca qzenwols zjeqe
Pafloquys vozif pru wtepgixs sbaqu

Sqo fenhavloit gejpaco
Ddi reyxiwruej morsoyu

Tetmisroij
Gitdecjuoy

Rabmhor
Mirydud

6. The Fresnel Effect

The Fresnel effect is a concept you’ve seen in previous chapters. As you may remember, the viewing angle plays a significant role in the amount of reflection you can see. What’s new in this chapter is that the viewing angle also affects refraction but in inverse proportion:

Llu vox luqau nukqeav xetbiycaup eff pomqezdoez
Wte qix tazia bifsuer sapcummaot arh xefkuxveij

Fezwujwoit enx Rettevviuc
Hezyaqlaih ads Kegzahjiuk

7. Adding Smoothness Using a Depth Texture

Light propagation varies for different transparent media. But for water, the colors with longer wavelengths (closer to infrared) quickly fade away as the light ray goes deeper. The bluish colors (closer to ultraviolet) tend to be visible at greater depths because they have shorter wavelengths.

Jepaz mux negl uvzod
Hesar kuq saxs uzdaf

Txidfawv ik pyo faduv't irdo
Hmepwamb ad tfi jexis'm unwo

Key Points

  • Reflection and refraction are important for realistic water and glass.
  • Rasterizing reflections and refraction will not produce as good a result as ray tracing. But when speed is a concern, then ray tracing is not often viable.
  • Because you’re using different view angles, you’ll need to create separate render passes to render the textures. For reflection, move the camera in the inverse direction from the plane to be reflected and flip the result.
  • You already knew about near and far clipping planes, but you can also add your own custom clipping planes. A negative clip distance from in the vertex function will result in the GPU discarding the vertex.
  • You can animate normal maps to provide water turbulence.
  • The Fresnel effect depends upon viewing angle and affects reflection and refraction in inverse proportion.

Where to Go From Here?

You’ve certainly made a splash with this chapter! If you want to explore more about water rendering, the references.markdown file in the resources folder for this chapter contains links to interesting articles and videos.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2026 Kodeco Inc.

You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now