Shader "Unlit/NewUnlitShader" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag // make fog work #pragma multi_compile_fog #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; UNITY_FOG_COORDS(1) float4 vertex : SV_POSITION; }; sampler2D _MainTex; float4 _MainTex_ST; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); UNITY_TRANSFER_FOG(o,o.vertex); return o; } fixed4 frag (v2f i) : SV_Target { // sample the texture fixed4 col = tex2D(_MainTex, i.uv); // apply fog UNITY_APPLY_FOG(i.fogCoord, col); return col; } ENDCG } } }
Shader "Unlit/NewUnlitShader"
with Shader "Shields/Transparent"
Tags { "RenderType"="Opaque" }
with Tags { "Queue"="Transparent" "RenderType"="Transparent" }
Tags { "Queue"="Transparent" "RenderType"="Transparent" }
add the line Blend SrcAlpha OneMinusSrcAlpha
. ZWrite Off
Tags { "Queue"="Transparent" "RenderType"="Transparent" }
UNITY_FOG_COORDS(1)
UNITY_TRANSFER_FOG(o,o.vertex)
UNITY_APPLY_FOG(i.fogCoord, col)
Properties { _MainTex ("Texture", 2D) = "white" {} }
Properties { _ShieldColor("Shield Color", Color) = (1, 0, 0, 1) _MainTex ("Transparency Mask", 2D) = "white" {} }
float4 _ShieldColor;
v2f vert (appdata v)
fixed4 frag (v2f i) : SV_Target { // sample the texture fixed4 col = tex2D(_MainTex, i.uv); return col; }
v2f
is the return value of the vertex shaders interpolated for the given pixel on the screen struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; };
uv
- pixel texture coordinatevertext
- pixel coordinate in screen coordinates fixed4 frag (v2f i) : SV_Target { // sample the texture fixed4 transparencyMask = tex2D(_MainTex, i.uv); return fixed4(_ShieldColor.r, _ShieldColor.g, _ShieldColor.b, transparencyMask.r); }
_ShieldColor
with the alpha channel taken from the red color of the texture. Properties { _ShieldIntensity("Shield Intensity", Range(0,1)) = 1.0 _ShieldColor("Shield Color", Color) = (1, 0, 0, 1) _MainTex ("Transparency Mask", 2D) = "white" {} }
float _ShieldIntensity; fixed4 frag (v2f i) : SV_Target { // sample the texture fixed4 transparencyMask = tex2D(_MainTex, i.uv); return fixed4(_ShieldColor.r, _ShieldColor.g, _ShieldColor.b, _ShieldIntensity * transparencyMask.r); }
Shader "Shields/Transparent" { Properties { _ShieldIntensity("Shield Intensity", Range(0,1)) = 1.0 _ShieldColor("Shield Color", Color) = (1, 0, 0, 1) _MainTex ("Transparency Mask", 2D) = "white" {} } SubShader { Tags { "Queue"="Transparent" "RenderType"="Transparent" } ZWrite Off Blend SrcAlpha OneMinusSrcAlpha Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float3 normal: NORMAL; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; sampler2D _MainTex; float4 _MainTex_ST; float4 _ShieldColor; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); return o; } float _ShieldIntensity; fixed4 frag (v2f i) : SV_Target { // sample the texture fixed4 transparencyMask = tex2D(_MainTex, i.uv); return fixed4(_ShieldColor.r, _ShieldColor.g, _ShieldColor.b, _ShieldIntensity * transparencyMask.r); } ENDCG } } }
Bias,
Scale, Power
shader Bias,
Scale, Power
Bias,
Scale, Power
Bias,
Scale, Power
. I expect that the reader has already learned how to add parameters to the shader and will not provide detailed instructions on how to do this. In case of difficulties, you can always see the full code at the end of the section.v2f vert (appdata v)
return value is the v2f
structure described earlier, and appdata
is the vertex parameters taken from the mesh. struct appdata { float4 vertex : POSITION; float3 normal: NORMAL; float2 uv : TEXCOORD0; };
vertex
- vertex
coordinates in local coordinatesnormal
- the surface normal specified for this vertexuv
- vertex texture coordinatesunity_ObjectToWorld
variable, and the world camera coordinates in the _WorldSpaceCameraPos
variable. Knowing this, you can calculate I with the following lines in the vertex shader code: float4 worldVertex = mul(unity_ObjectToWorld, v.vertex); float3 I = normalize(worldVertex - _WorldSpaceCameraPos.xyz);
float3 normWorld = normalize(mul(unity_ObjectToWorld, v.normal));
float fresnel = _Bias + _Scale * pow(1.0 + dot(I, normWorld), _Power);
saturate
function: float fresnel = saturate(_Bias + _Scale * pow(1.0 + dot(I, normWorld), _Power));
struct v2f { float2 uv : TEXCOORD0; float intensity : COLOR0; float4 vertex : SV_POSITION; };
COLOR0
is semantics, the explanation of what it is is beyond the scope of this article, those interested can read about semantics in hlsl). v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); float4 worldVertex = mul(unity_ObjectToWorld, v.vertex); float3 normWorld = normalize(mul(unity_ObjectToWorld, v.normal)); float3 I = normalize(worldVertex - _WorldSpaceCameraPos.xyz); float fresnel = saturate(_Bias + _Scale * pow(1.0 + dot(I, normWorld), _Power)); o.intensity = fresnel; return o; } float _ShieldIntensity; fixed4 frag (v2f i) : SV_Target { // sample the texture fixed4 transparencyMask = tex2D(_MainTex, i.uv); return fixed4(_ShieldColor.r, _ShieldColor.g, _ShieldColor.b, (_ShieldIntensity + i.intensity) * transparencyMask.r); }
_ShieldIntensity
and i.intensity
even in the vertex shader, so i.intensity
do it. Shader "Shields/Fresnel" { Properties { _ShieldIntensity("Shield Intensity", Range(0,1)) = 1.0 _ShieldColor("Shield Color", Color) = (1, 0, 0, 1) _MainTex ("Transparency Mask", 2D) = "white" {} _Bias("Bias", float) = 1.0 _Scale("Scale", float) = 1.0 _Power("Power", float) = 1.0 } SubShader { Tags { "Queue"="Transparent" "RenderType"="Transparent" } ZWrite Off Blend SrcAlpha OneMinusSrcAlpha Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float3 normal: NORMAL; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float intensity : COLOR0; float4 vertex : SV_POSITION; }; sampler2D _MainTex; float4 _MainTex_ST; float4 _ShieldColor; float _ShieldIntensity; float _Bias; float _Scale; float _Power; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); float4 worldVertex = mul(unity_ObjectToWorld, v.vertex); float3 normWorld = normalize(mul(unity_ObjectToWorld, v.normal)); float3 I = normalize(worldVertex - _WorldSpaceCameraPos.xyz); float fresnel = saturate(_Bias + _Scale * pow(1.0 + dot(I, normWorld), _Power)); o.intensity = fresnel + _ShieldIntensity; return o; } fixed4 frag (v2f i) : SV_Target { // sample the texture fixed4 transparencyMask = tex2D(_MainTex, i.uv); return fixed4(_ShieldColor.r, _ShieldColor.g, _ShieldColor.b, i.intensity * transparencyMask.r); } ENDCG } } }
public class ShieldHitter : MonoBehaviour { private static int[] hitInfoId = new[] { Shader.PropertyToID("_WorldHitPoint0"), Shader.PropertyToID("_WorldHitPoint1"), Shader.PropertyToID("_WorldHitPoint2") }; private static int[] hitTimeId = new[] { Shader.PropertyToID("_HitTime0"), Shader.PropertyToID("_HitTime1"), Shader.PropertyToID("_HitTime2") }; private Material material; void Start() { if (material == null) { material = this.gameObject.GetComponent<MeshRenderer>().material; } } int lastHit = 0; public void OnHit(Vector3 point, Vector3 direction) { material.SetVector(hitInfoId[lastHit], point); material.SetFloat(hitTimeId[lastHit], Time.timeSinceLevelLoad); lastHit++; if (lastHit >= hitInfoId.Length) lastHit = 0; } void OnCollisionEnter(Collision collision) { OnHit(collision.contacts[0].point, Vector3.one); } }
using UnityEngine; [ExecuteInEditMode] public class CameraControls : MonoBehaviour { private const int minDistance = 25; private const int maxDistance = 25; private const float minTheta = 0.01f; private const float maxTheta = Mathf.PI - 0.01f; private const float minPhi = 0; private const float maxPhi = 2 * Mathf.PI ; [SerializeField] private Transform _target; [SerializeField] private Camera _camera; [SerializeField] [Range(minDistance, maxDistance)] private float _distance = 25; [SerializeField] [Range(minTheta, maxTheta)] private float _theta = 1; [SerializeField] [Range(minPhi, maxPhi)] private float _phi = 2.5f; [SerializeField] private float _angleSpeed = 2.0f; [SerializeField] private float _distanceSpeed = 2.0f; // Update is called once per frame void Update () { if (_target == null || _camera == null) { return; } if (Application.isPlaying) { if (Input.GetKey(KeyCode.Q)) { _distance += _distanceSpeed * Time.deltaTime; } if (Input.GetKey(KeyCode.E)) { _distance -= _distanceSpeed * Time.deltaTime; } Mathf.Clamp(_distance, minDistance, maxDistance); if (Input.GetKey(KeyCode.A)) { _phi += _angleSpeed * Time.deltaTime; } if (Input.GetKey(KeyCode.D)) { _phi -= _angleSpeed * Time.deltaTime; } _phi = _phi % (maxPhi); if (Input.GetKey(KeyCode.S)) { _theta += _angleSpeed * Time.deltaTime; } if (Input.GetKey(KeyCode.W)) { _theta -= _angleSpeed * Time.deltaTime; } _theta = Mathf.Clamp(_theta, minTheta, maxTheta); Vector3 newCoords = new Vector3 { x = _distance * Mathf.Sin(_theta) * Mathf.Cos(_phi), z = _distance * Mathf.Sin(_theta) * Mathf.Sin(_phi), y = _distance * Mathf.Cos(_theta) }; this.transform.position = newCoords + _target.position; this.transform.LookAt(_target); if (Input.GetMouseButtonDown(0)) { Ray ray = _camera.ScreenPointToRay(Input.mousePosition); RaycastHit hit; var isHit = Physics.Raycast(ray, out hit); if (isHit) { ShieldHitter handler = hit.collider.gameObject.GetComponent<ShieldHitter>(); Debug.Log(hit.point); if (handler != null) { handler.OnHit(hit.point, ray.direction); } } } } } }
distance
- the fraction of the distance to the point of contact with the maximum, [0, 1]time
- the fraction of the lifetime of the maximum, [0, 1] float t0 = saturate((_Time.y - _HitTime0) / _HitDuration); float d0 = saturate(distance(worldVertex.xyz, _WorldHitPoint0.xyz) / (_MaxDistance)); float t1 = saturate((_Time.y - _HitTime1) / _HitDuration); float d1 = saturate(distance(worldVertex.xyz, _WorldHitPoint1.xyz) / (_MaxDistance)); float t2 = saturate((_Time.y - _HitTime2) / _HitDuration); float d2 = saturate(distance(worldVertex.xyz, _WorldHitPoint2.xyz) / (_MaxDistance));
float hitIntensity = (1 - t0) * ((1 / (d0)) - 1) + (1 - t1) * ((1 / (d1)) - 1) + (1 - t2) * ((1 / (d2)) - 1);
o.intensity = fresnel + _ShieldIntensity + hitIntensity;
Cull off
after ZWrite Off
. But here too the problem awaits us: float dt = dot(I, normWorld); fresnel = saturate(_Bias + _Scale * pow(1.0 - dt * dt, _Power));
o.uv = TRANSFORM_TEX(v.uv, _MainTex) + _Time.x / 6;
Shader "Shields/FresnelWithHits" { Properties { _ShieldIntensity("Shield Intensity", Range(0,1)) = 1.0 _ShieldColor("Shield Color", Color) = (1, 0, 0, 1) _MainTex ("Transparency Mask", 2D) = "white" {} _Bias("Bias", float) = 1.0 _Scale("Scale", float) = 1.0 _Power("Power", float) = 1.0 _WorldHitPoint0("Hit Point 0", Vector) = (0, 1, 0, 0) _WorldHitTime0("Hit Time 0", float) = -1000 _WorldHitPoint1("Hit Point 1", Vector) = (0, 1, 0, 0) _WorldHitTime1("Hit Time 1", float) = -1000 _WorldHitPoint2("Hit Point 2", Vector) = (0, 1, 0, 0) _WorldHitTime2("Hit Time 2", float) = -1000 _HitDuration("Hit Duration", float) = 10.0 _MaxDistance("MaxDistance", float) = 0.5 } SubShader { Tags { "Queue" = "Transparent" "RenderType" = "Transparent" } ZWrite Off Cull Off Blend SrcAlpha OneMinusSrcAlpha Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float3 normal: NORMAL; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float intensity : COLOR0; float4 vertex : SV_POSITION; }; sampler2D _MainTex; float4 _MainTex_ST; float4 _ShieldColor; float _ShieldIntensity; float _Bias; float _Scale; float _Power; float _MaxDistance; float _HitDuration; float _HitTime0; float4 _WorldHitPoint0; float _HitTime1; float4 _WorldHitPoint1; float _HitTime2; float4 _WorldHitPoint2; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex) + _Time.x / 6; float4 worldVertex = mul(unity_ObjectToWorld, v.vertex); float3 normWorld = normalize(mul(unity_ObjectToWorld, v.normal)); float3 I = normalize(worldVertex - _WorldSpaceCameraPos.xyz); float fresnel = 0; float dt = dot(I, normWorld); fresnel = saturate(_Bias + _Scale * pow(1.0 - dt * dt, _Power)); float t0 = saturate((_Time.y - _HitTime0) / _HitDuration); float d0 = saturate(distance(worldVertex.xyz, _WorldHitPoint0.xyz) / (_MaxDistance)); float t1 = saturate((_Time.y - _HitTime1) / _HitDuration); float d1 = saturate(distance(worldVertex.xyz, _WorldHitPoint1.xyz) / (_MaxDistance)); float t2 = saturate((_Time.y - _HitTime2) / _HitDuration); float d2 = saturate(distance(worldVertex.xyz, _WorldHitPoint2.xyz) / (_MaxDistance)); float hitIntensity = (1 - t0) * ((1 / (d0)) - 1) + (1 - t1) * ((1 / (d1)) - 1) + (1 - t2) * ((1 / (d2)) - 1); o.intensity = fresnel + _ShieldIntensity + hitIntensity; return o; } fixed4 frag (v2f i) : SV_Target { // sample the texture fixed4 transparencyMask = tex2D(_MainTex, i.uv); return fixed4(_ShieldColor.r, _ShieldColor.g, _ShieldColor.b, saturate(i.intensity * transparencyMask.r)); } ENDCG } } }
Source: https://habr.com/ru/post/352228/
All Articles