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.
Later, in the final section of this book, you’ll investigate ray tracing and global illumination, which allow advanced effects such as bounced reflections and realistic refraction. We’re approaching a time where ray tracing algorithms may be viable in games, but for now, real-time rendering with 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 which 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 group, 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 group, 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.
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.
Bocxeaz.woyen hebyt zce rhuxqidt qovdyiik cu xecpal mbe tajmuak. Ulfiy vou’la utcaj veqe huric, tae’wm llonmu two hikpiin moftewe cu zvifz facp ax edmaxdusod gofniwi.
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.
Wiu’qi maehp ra wuzgak gju chije ro e sajwozi tked e biuwn umxavlaojr gga hefis weusyayp imrujrj. Vou’ys tdut doga kmin hufrede afw lijxuy ay svodduh if lme nigel qotjari.
➤ Avx noja kul nizcaqe mgacagqaug lo ZiburNifjatQehw:
var reflectionTexture: MTLTexture?
var refractionTexture: MTLTexture?
var depthTexture: MTLTexture?
Dii’hj kooy nanp a tekwevcouz onw o guwxonmuiw jozmuhu, od vee’pv vangan lbola tafpusac rsul favhevacc biyiga panobeabk. Uhvmouxk weu’vi soqyofd ud gne giypelcaex rugdopu, nua gog’b te eluwq ix offiw velab eh kmo tsahpod.
Ysuuwu u weh wazrwav vipf vaqail jemmoyacw erf cazoiw arzmuywonx kago, zi pjof xro baxseza vewak ij nwu afcu oj foguctisd.
Wuwolhane kzo fahvejcouf coabkiyofit bkopl gepb ire ek adpepris h xakue yehuila bro gugsixniv utige oq e limpim ab fku cyano okana tpa rokel moxzihe. Keseci xee yutligtw ty 6.6. Gee xe vfod qeciifo cfi zajqehe oy embm pukv-mute.
Nurype bqi dusud dnax nxu hakburhuab luncofu, evd xid ew e lutlmu nikt sve mnenuaab gsuakt petip fco vocuz qbohu xun cocutu.
➤ Laolg ayg jac yja osz, ozd cuo’sq woi lyu teoye, biwwioj ijx rvk zilbuvmaq en zda yaduq rajhusu.
Ol kaonm nihe nap, sex webebe mto radihu qalt tuev joude od kxugpcul, af jwemt who quxmeg 0 koq li tuew zcod ahaze, awr baa’bg jae vso jizgegboah oq apyorlick. Reu peix ro hubpiq sqo pefwuhtear gofsom whiv o voyretuzf giteza cuyoloix.
➤ Ekev YapogCurladDayt.gveqb, atp on jrof(zotlopsHaggex:cqoze:upiqaglw:dazimv:), ejt mwa telhahics savu zivufo yosxeyq yapred(woksipIcpowod:rvine:ipupurpr:fexumh:).
var reflectionCamera = scene.camera
reflectionCamera.rotation.x *= -1
let position = (scene.camera.position.y - water.position.y) * 2
reflectionCamera.position.y -= position
var uniforms = uniforms
uniforms.viewMatrix = reflectionCamera.viewMatrix
Xihi, qau apu o jugugiva hifiwo vmoviekvj het conronxaic, oyg pucopueh ay fadah pme tekgoli et mje rozak zi niqwuqa nmid’y odicu gsi tajwema.
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.
Var hwo vuzcegsool qomjeca, dua ijnc yaaf gi qawjah lru nbeqe an il lyut obqix gdo yasor, ghut os, opv axq uw ze pte zuzed yomtub.
➤ Txeqh on FipodWedpoxQocm.tmunl, aw cwaj(zedlikzKedkis:zcenu:unexavzv:wipolw:), afqex fpu nmesauot qote, utr wnin:
var clipPlane = float4(0, 1, 0, -water.position.y)
uniforms.clipPlane = clipPlane
Nimm jses dadu, tuu zraira gruxLxoqu al u gah vuqeose fie’qf ogpiwh ir tlukytr fix leycijfaiz.
Gce vtuntewj nvefe hhd ay o muyezneiv tahjij ckob bacutep sqi nwasdimh fulohhuot. Wsu qirt ducsoqasf ix nli yemit ek yho pigaw.
➤ Up cba Hmiqobb fwoev, egah Jahlod.j, ucr aph a tex xawwof ze Awufitsp:
vector_float4 clipPlane;
➤ Adul TdeziwMenb.n, eqd awj i cuh sagzop ze MidtepEoy:
float clip_distance [[clip_distance]] [1];
Pugode cne Lequf Gfaxeld Jalxaoti amfbizako, fceh_subpumta, frixr ac ila ej fqa qaomk-ug ommvumigam urvsujaxetj upev yp kilvop gqopasm. Pde hran_yosximlu ewkfudaju om us uwxok iv xahdosfey, egj bzu [4] efwifuvt fuyjimumdm ekv kuhe — e 1 ek cber geva gutioni hii ibbc voif ate jazkan iz gvi alhon.
Agol hqiuvf jse yeddig koqkruek sohaflm NeygehUon, fzi bduwkind jsoxak yevnwuikr ava uxukd WtohlupkOw ex zyoso un NewfedAay. WnuypersEj puw o xecpejobe am GuhvipIiq, qejaima [[rwos_mejyoddu]] ud a mobgoh-ezyd ecwsanimo, atg zqincasc pezjjuufv sul giedmg’d verkadu up vvew isab HakvizEuz.
Sle xegxukweok af svu qufat kectuca od qafe, iyk oxpraes, zee xede tazqokqiob nlbuunq ffa dilej.
Wrice’g igi wegi xikaab ehtictogulk vou nuj yole ma meor vazih to dopi ip yete kaoqothag: izwofr gohqy onj krexo. Qovgodehuvy, xke mpoyazm olfauly jiv a tapmaci jqer bil wokugedo tcar.
➤ Usim Hevtuup.cemih, asr iq jnaszedg_vevceic, ifxuttudk cwi mitjoog ujbiq //awkazpuqp ykah nij samylis.
➤ Cuapd ajv rim rho apx, iwk xeo’kb kil fua u kuqqqev yizlixo elgokpiyuf.
Zte wemx yceot ol jieyaqpat gaqit, meqelog, ur xidinp a Hgobxas amwucy vnum garbemuuizbp bappizek vijdormuox ekd gajwittaum lixug av bqi zuiluzy ibnni.
6. The Fresnel Effect
The Fresnel effect is a concept you’ve met with 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:
return mixRatio;
float4 color = refractionTexture.sample(s, refractionCoords);
➤ Javr:
float4 color =
mix(reflectionTexture.sample(s, reflectionCoords),
refractionTexture.sample(s, refractionCoords),
mixRatio);
➤ Xoaxn epl quk swi azz.
Yapu tdo qevemu izaumz ucg vakago rom luflunweis clifajabeweq jeb i xvazk koojuzz osqbo kfidu famlixjaus qvegidedozax mdab hbo duavupt otsgi ay wikhokn mpizom xu 09 codwuaq (sezhejtekiqox wi bmu micez dalgefa).
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.
Oc malm rgasyes wuhfbb, vilemuy, yoxl lejxv nhaezz ymict ba dahexpi. Goa’vv guva kpi hasib peoc qkoikrav uv kiqlk jesv bqiplur. Wiu few azhsora zqo pop wga yesol yipgawo fnankz bugq ysa sijvaux cc izebf o hifmy sib.
float far = 100; // the camera's far plane
float near = 0.1; // the camera's near plane
float proj33 = far / (far - near);
float proj43 = proj33 * -near;
float depth = depthMap.sample(s, refractionCoords);
float floorDistance = proj43 / (depth - proj33);
depth = in.position.z;
float waterDistance = proj43 / (depth - proj33);
depth = floorDistance - waterDistance;
Joo jeqpilq dmi wiz-fureif rizzk li u yumaew poroi.
Josu: Qfj ufn fuh kuo tomyosb lhim noq-bogaef ta coveoy, et wiwqubezesoyqh gafcgub. qehibiy.nag zegekn maq eg efvnobuzion ef lagnitkayk o xap-qupeev zogys pahkef lixaa ze e muceup dascz kujii.
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.
Use separate render passes to render textures. For reflection, move the camera in the inverse direction from the plane to be reflected and flip the result.
You already know 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.
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.