Restoration Design
One of the challenges that the project needed to overcome was delivering a sense of restoring the dead forest in which you play and have that feel as satisfying as possible. To that end I pitched a system of feedback that would be delivered to the player.
In vague terms, the feedback comes together to turn a section of corrupted, dead forest into a lush, green variation of itself. More specifically, A texture painter paints onto a render target that can be sampled as a mask by several shaders and tweened animations, VFX and post processing. The channels of feedback were specifically:
An environment shader that changes ground textures by sampling this mask. In this case, swapping from brown/grey textures to Green.
Why?
Artist friendly
More Dynamic
Highly scalable
Visually interesting
HLSL
The system paints to a render target, which I then sample. I take the world coordinate of a painted position on a canvas within the game world. I then paint to a correspondiing position on the mask which can be sampled later by various shaders.
Texture paint shader:
fixed4 frag (v2f i) : SV_Target{
if(_PrepareUV > 0 ){
return float4(0, 0, 1, 1);
}
float4 col = tex2D(_MainTex, i.uv);
float4 res = float4(0,0,0,1);
float f = 0;
//R: Ground
if (_PainterColor.r > 0.0){
f = mask(i.worldPos, _PainterPosition, _Radius, _Hardness);
res.r = lerp(col.r, _PainterColor.r, f * _Strength);
}
//G: Overgrowth
if (_PainterColor.g > 0.0){
float d = anCircle(i.worldPos, _PainterPosition, _Radius, _Width);
float ringmask = d < 0.0 ? 1.0 : 0.0;
float edgefade = 1 - exp((-6 * _Hardness) * abs(d)); // my smoothstep
_PainterColor.g = saturate(_PainterColor.g);
res.g = _PainterColor.g * ringmask * edgefade;
}
//B: Foliage
if (_PainterColor.b > 0.0){
res.b = lerp(col.b, _PainterColor.b, f * _Strength);
}
return res;
}
The red channel is used for the texture painted materials, like the ground and walls.The blue channel is used for the vertex shaders and defines where the vegetation is grown and where it is hidden. The green channel is used for overgrowth, in this case I cause the vegetation to gain some additional height in any section already defined as grown by the blue channel. I paint a ring into the green channel which dissipates over time. This adds some more life to the effect and sells the aesthetics of restoring the forest better.
Shadergraph
Grass vertex shader
Here is the shadergraph for the vertex shader which controls the foliage. It samples the mask twice, once at world vertex position and once at object pivot position. I then perform some calculations to either show or hide the mesh.
Ground fragment shader
Here's the shadergraph for the ground objects. Here I sample the world position of the object once and transform its coordinates based on the transform of the canvas to which the texture painter is painting. I then lerp between two sets textures based on the mask and some vertex painting.
Automatic setup
It was important that this tool wouldn't impact our artists and would instead empower them to be more creative when set dressing the levels. I spent some additional time creating redundancies and an automatic set up for the Restoration System. I made it so that to set everything up you just add the script to the level prefab. No other set up is required for the artists. The service will add every component to the level necessary for the system to work. The only requirements are to physically add some painters to the scene, which are also just a single script.
One-click set up
Dynamic for every level
Works on older levels
No workflow changes