Shader – Mosnters Rising (iOS)
I worked on Monsters Rising (iOS) as a Technical Artist and was responsible for writing all the shaders along with lighting and vfx. Monsters Rising is my first mobile title but having some prior experience through personal exploration and research adapting to mobile hardware wasn’t too big of an issue. I am very passionate about writing shaders and had high personal expectations. Some of my goals were to bring the post processing techniques used in the console space to mobile. I spent quite a bit of time working on the post processing and lighting to get the mood and feel of the game set out by the art director. Most of my time went into researching the PowerVR hardware so that our shaders can be as efficient as possible. This involved reading tech docs, watching presentations and profiling various shaders. All shaders were written in Cg as Unity can cross compile cg to various platforms. Below are some of the shaders I created for the game.
You can find out more about the game at: www.monstersrising.com
You can download the game from the App store from here: https://itunes.apple.com/ca/app/monsters-rising/id692484676?mt=8
Our post process mainly consists of Bleach Bypass and Bloom. The Bleach Bypass gives us the added contrast and makes the scene pop more. The elements that bloom are determined by how bright the pixels are and also by a mask stored in the alpha channel of the display buffer (used for things like windows as they are not bright enough to bloom, if we made it too bright then they would look too hot and would create a lot of visual noise). The post process is selectively applied only to the world and the charaters are ignored as they looked better without it. This was achieved by storing 2 range of values in the alpha channel. 0% to 50% alpha determined how much Bleach Bypass was applied to the scene (0% being full bleach bypass and 50% being none) and 50% to 100% determined how much an element would bloom(50% meant no bloom and 100% meant full bloom). Effectively this meant anything with an alpha value of 50% would be ignored by our post process (visually only, not computationally). Below is a shot from a portion of the game showing the difference in visuals with and without post processing.
In Monsters Rising, the player characters had a line of sight which determined which enemies they could see and which enemies they couldn’t. I worked closely with one of our programmers to build a system that could help us visualize the line of sight and also be used as a potential feature (we felt it was unnecessary feature in the end and decided not to go ahead with it). This system was built so it ran not only in the editor but the iPad as well. Our programmer generated a “visibility map” which was a 2d representation of what the player characters could see and could not see. I used this “visibility map” and projected it onto the assets in world space from the top. It helped us debug our visibility system greatly and fine tune it to better the gameplay. Below is the system in action. The desaturated areas are not visible to the player unit while the saturated areas are what they can currently see from where they are. The system updates over a couple of frames rather than every frame in order to make it run efficiently on the iPad so that the game is playable at an optimum frame rate.
This was an interesting shader to create. We were creating spawning sequences and the idea of the army soldier roping in from a helicopter came up. Originally the rope was planned to be rigged and animated and could have been potentially quite expensive and time consuming to create. I did a bit of exploration and was able to achieve the entire rope sequence through a vertex shader solving the problem in a faster and cheaper way. The rope animation is done through a couple of animated sin waves. The texture coordinates of the rope are mapped such that the top of the rope corresponds with v = 1 and the bottom with v = 0. This allowed me to use the uv coordinates as a gradient mask with which I could do some math create a health bar like mask and use this mask to determine which part of the rope is affected by the sin wave animation and which parts aren’t. This mask is controlled by a single floating point value which is animated and synced with the animation of the army soldier sliding down. The result can be viewed below.
The designers required an energy barrier that is scalable horizontally to block certain regions of the world. When an object is stretched in one axis, the texture gets stretched along with it. To avoid this I wrote a shader that uses the objects xy position in object space as uv coordinates. Since the object can be rotated, world space projection wouldn’t work. The fx itself was created by using scrolling textures. This gave the designers flexibility in placing the barriers without having to worry about anything. You can see this in action below.
Cop Car Siren:
Cops were plentiful in monsters rising and so were cop cars. The cop cars needed to feel alive and we wanted the sires to animate which was achieved purely with shaders. The siren n the cop car was masked using vertex colors. the red channel masked the red part of the siren and the green channel masked the blue part of the siren. We also utilized the blue and alpha channel of the vertex colors to create a mask for the siren lights to splash on the car as they are animating. The first version of the shader had all these features but it had a draw back where all the cop car sirens would end up being in sync and this made it look very artificial. This is because the value of time for all the cars would be the same and also the material on them is instanced so that the models batch together which mean’t we could not specify unique or random offsets. To solve this issue in the next version of the shader, I offseted the time value by world space position of the vertex. The position values were rounded. For e.g. if a vertex was located in (1.4245, 55.2332) in x and z (as unity uses y up) it would round those values to (1,55) which meant all vertices close to one another would share the same value therefore offseting time by the same value. With the time value offset I was able to randomize the sirens which can be viewed in the video below.