worldPos
field to the Unity 5 surface shader's Input
structure. struct Input { float2 uv_MainTex; float3 worldPos; };
Albedo
property in the SurfaceOutputStandard
structure. float _ConstructY; fixed4 _ConstructColor; void surf (Input IN, inout SurfaceOutputStandard o) { if (IN.worldPos.y < _ConstructY) { fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color; o.Albedo = c.rgb; o.Alpha = ca; } else { o.Albedo = _ConstructColor.rgb; o.Alpha = _ConstructColor.a; } o.Metallic = _Metallic; o.Smoothness = _Glossiness; }
#pragma surface surf Unlit fullforwardshadows inline half4 LightingUnlit (SurfaceOutput s, half3 lightDir, half atten) { return _ConstructColor; }
SurfaceOutput
, which was used in Unity 4. If we want to create our own lighting model that works with PBR and global illumination, then we need to implement a function that receives SurfaceOutputStandard
as input. In Unity 5, the following function is used for this: inline half4 LightingUnlit (SurfaceOutputStandard s, half3 lightDir, UnityGI gi) { return _ConstructColor; }
gi
parameter here refers to the global illumination (global illumination), but in our unlit shader it does not perform any tasks. This approach works, but it has a big problem. Unity does not allow the surface shader to selectively change the lighting function. We cannot apply standard Lambert lighting to the lower part of the object and at the same time make the upper part unlit. You can assign a single lighting function for the entire object. We have to change the way the object is rendered depending on its position.building
), which we define as a surface function. This variable can be checked by our new lighting function. int building; void surf (Input IN, inout SurfaceOutputStandard o) { if (IN.worldPos.y < _ConstructY) { fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color; o.Albedo = c.rgb; o.Alpha = ca; building = 0; } else { o.Albedo = _ConstructColor.rgb; o.Alpha = _ConstructColor.a; building = 1; } o.Metallic = _Metallic; o.Smoothness = _Glossiness; }
building
to change the way lighting is calculated. The part of the object that is currently being constructed will be unlit, and the rest will be correctly calculated lighting. If we want our material to use PBR, we cannot rewrite all the code for photorealistic lighting. The only reasonable solution is to call the standard lighting function, which is already implemented in Unity.#pragma
that defines the use of the PBR lighting function is as follows: #pragma surface surf Standard fullforwardshadows
LightingStandard
. This feature is in the UnityPBSLighting.cginc
file, which you can connect if necessary.LightingCustom
. Under normal circumstances, it simply calls the standard Unite PBR function called LightingStandard
. However, if necessary, it uses the previously defined LightingUnlit
. inline half4 LightingCustom(SurfaceOutputStandard s, half3 lightDir, UnityGI gi) { if (!building) return LightingStandard(s, lightDir, gi); // Unity5 PBR return _ConstructColor; // Unlit }
inline void LightingCustom_GI(SurfaceOutputStandard s, UnityGIInput data, inout UnityGI gi) { LightingStandard_GI(s, data, gi); }
discard
keyword. With it, you can draw only the border around the top of the model: void surf (Input IN, inout SurfaceOutputStandard o) { if (IN.worldPos.y > _ConstructY + _ConstructGap) discard; ... }
Cull Off
viewDir
in the surface shader) and the triangle normal. If it is negative, then the triangle is turned away from the camera. That is, we see his "wrong side" and can render it in solid color. struct Input { float2 uv_MainTex; float3 worldPos; float3 viewDir; }; void surf (Input IN, inout SurfaceOutputStandard o) { viewDir = IN.viewDir; ... } inline half4 LightingCustom(SurfaceOutputStandard s, half3 lightDir, UnityGI gi) { if (building) return _ConstructColor; if (dot(s.Normal, viewDir) < 0) return _ConstructColor; return LightingStandard(s, lightDir, gi); }
void surf (Input IN, inout SurfaceOutputStandard o) { float s = +sin((IN.worldPos.x * IN.worldPos.z) * 60 + _Time[3] + o.Normal) / 120; if (IN.worldPos.y > _ConstructY + s + _ConstructGap) discard; ... }
_ConstructY
parameter to the material. The shader will take care of the rest. You can control the speed of the effect either by code, or by using an animation curve. In the first version, you can fully control its speed. public class BuildingTimer : MonoBehaviour { public Material material; public float minY = 0; public float maxY = 2; public float duration = 5; // Update is called once per frame void Update () { float y = Mathf.Lerp(minY, maxY, Time.time / duration); material.SetFloat("_ConstructY", y); } }
Source: https://habr.com/ru/post/331576/
All Articles