雖然不是什麼新技術,但是是老技術啊,對啊,就是這麼驢唇不對馬嘴,就是這麼的無恥,先發個招聘:
坐标山東青島市北,招聘日系畫師,spine動畫師。
然後再說一下QQ群,山東手遊研發聚集地335772557,進群先看公告,要是抱着我要學習的心态進群的話,那你就失望了,因為是個死群。
偶爾心情好的是時候會發個技術連結。
扯的雖然不多,但是要進入話題了。
測試來源于網際網路,若侵權請告知删除。入群請不要跟我要模型貼圖
由于是邊寫邊做技術記錄,是以就不先放效果圖了
先說一下思路,就是在shader中重開一個pass做shadow的渲染,思路就是這麼簡單
第一個pass就是原來模型的渲染,這個就不說了,這個效果跟個人需求相關,我這裡用了surfaceshader的standard來做測試了。
先上一下這個此事開頭的shader吧
效果圖:
Shader "ShaderStore/Shadow/ShadowFlatOnPlane"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
}
SubShader
{
Tags { "RenderType"="Opaque" "ForceNoShadowCasting"="True"}
LOD 100
CGPROGRAM
#pragma surface surf Standard noshadow
#pragma target 3.0
sampler2D _MainTex;
struct Input
{
float2 uv_MainTex;
};
half _Glossiness;
half _Metallic;
fixed4 _Color;
void surf (Input IN, inout SurfaceOutputStandard o)
{
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
ENDCG
}
}
接下來我們提個需求,shadow的顔色可以修改
首先需要在Properties裡貼圖對應的參數,友善調節
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
_ShadowColor("Shadow Color",Color) = (1,0,0,1)
}
然後我們繼續,新增一個pass去修改模型的頂點,讓模型的頂點投影到世界中,首先,shadow是平的,也就是worldposition的y要設定為0
将模型空間的頂點轉到世界中去,然後把y=0,在轉回模型空間。
float4 worldPos = mul(_Object2World,v.vertex);
worldPos.y = 0;
float4 localPos = mul(_World2Object,worldPos);
這樣操作之後得到的結果是
Shader "ShaderStore/Shadow/ShadowFlatOnPlane"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
_ShadowColor("Shadow Color",Color) = (1,0,0,1)
}
SubShader
{
Tags { "RenderType"="Opaque" "ForceNoShadowCasting"="True"}
LOD 100
CGPROGRAM
#pragma surface surf Standard noshadow
#pragma target 3.0
sampler2D _MainTex;
struct Input
{
float2 uv_MainTex;
};
half _Glossiness;
half _Metallic;
fixed4 _Color;
void surf (Input IN, inout SurfaceOutputStandard o)
{
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
ENDCG
//ShadowFlatOnPlane
Pass
{
OffSet -1,-1
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex:POSITION;
};
struct v2f
{
float4 pos:SV_POSITION;
};
fixed4 _ShadowColor;
v2f vert(appdata v)
{
v2f o;
float4 worldPos = mul(unity_ObjectToWorld,v.vertex);
worldPos.y = 0;
float4 localPos = mul(unity_WorldToObject,worldPos);
o.pos = UnityObjectToClipPos(localPos);
return o;
}
fixed4 frag(v2f i):SV_Target
{
return _ShadowColor;
}
ENDCG
}
}
}
然後新的問題出現了,陰影着實的在時間y=0的平面上,跟燈光方向無關。新需求就是希望影子投影與燈光的方向有關
(這篇博文是不是很流水賬,呵呵呵,主要的意圖就是招聘)
v2f vert(appdata v)
{
v2f o;
float3 lightDir = -normalize(_WorldSpaceLightPos0.xyz);
loat4 worldPos = mul(unity_ObjectToWorld,v.vertex);
worldPos.x -= worldPos.y/lightDir.y*lightDir.x;
worldPos.z -= worldPos.y/lightDir.y*lightDir.z;
worldPos.y = 0;
o.pos = mul(UNITY_MATRIX_VP,worldPos);
return o;
}
然後新問題:影子是不是要透明一些?
//ShadowFlatOnPlane
Pass
{
Tags{"RenderType"="Transparent" "Queue"="Transparent"}
OffSet -1,-1
Blend SrcAlpha OneMinusSrcAlpha
ZWrite Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
新問題帶來的新需求,解決方案stencil
//ShadowFlatOnPlane
Pass
{
stencil
{
Ref 1
Comp NotEqual
Pass Replace
}
Tags{"RenderType"="Transparent" "Queue"="Transparent"}
OffSet -1,-1
Blend SrcAlpha OneMinusSrcAlpha
ZWrite Off
CGPROGRAM
看似基本的效果也差不多了,我高興的複制了一個,錯了下位置,然後又有了新的問題,或許對于有些項目來說也不是個問題
怎麼解決呢?還是stencil吧,不同的材質給個不同的ref
Shader "ShaderStore/Shadow/ShadowFlatOnPlane"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
_ShadowColor("Shadow Color",Color) = (1,0,0,1)
_Ref("Stencil Ref",Int) = 1
}
......
//ShadowFlatOnPlane
Pass
{
stencil
{
Ref [_Ref]
Comp NotEqual
Pass Replace
}
......
現在基本上的問題都搞定了,我有興緻使然,轉了下地面的plane,呵呵。。
新需求,然影子透到指定的plane平面吧,看到了哈,是平面,曲面的話我也不知道,shadowmap去幹吧
.....我突然卡殼。。。這個需求過會再說吧。。。新需求,陰影從腳底到頭頂有漸變過渡
struct v2f
{
float4 pos:SV_POSITION;
float Value:TEXCOORD0;
};
fixed4 _ShadowColor;
v2f vert(appdata v)
{
v2f o;
float3 lightDir = -normalize(_WorldSpaceLightPos0.xyz);
float4 worldPos = mul(unity_ObjectToWorld,v.vertex);
worldPos.x -= worldPos.y/lightDir.y*lightDir.x;
worldPos.z -= worldPos.y/lightDir.y*lightDir.z;
worldPos.y = 0;
o.pos = mul(UNITY_MATRIX_VP,worldPos);
o.Value = 1-worldPos.z/14.0;
return o;
}
fixed4 frag(v2f i):SV_Target
{
return _ShadowColor*i.Value;
}
再來說上面遺留的問題,如何投影到custom的plane上呢,把頂點轉到planer,然後處理,在轉回world,再mvp。。。
這個操作免不了C#的參數傳入
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[ExecuteInEditMode]
public class ShadowFlatOnPlane : MonoBehaviour {
public Transform ShadowPlane;
public Material[] ShadowMats;
// Use this for initialization
void Start () {
foreach (Material mat in ShadowMats)
{
mat.SetMatrix("_World2Ground", ShadowPlane.GetComponent<MeshRenderer>().worldToLocalMatrix);
mat.SetMatrix("_Ground2World", ShadowPlane.GetComponent<MeshRenderer>().localToWorldMatrix);
}
}
private void Update()
{
Start();
}
}
struct v2f
{
float4 pos:SV_POSITION;
float Value:TEXCOORD0;
};
fixed4 _ShadowColor;
float4x4 _World2Ground;
float4x4 _Ground2World;
v2f vert(appdata v)
{
v2f o;
float3 lightDir = -normalize(_WorldSpaceLightPos0.xyz);
lightDir = normalize(mul(_World2Ground,float4(lightDir,0)).xyz);
float4 worldPos = mul(unity_ObjectToWorld,v.vertex);
worldPos = mul(_World2Ground,worldPos);
worldPos.xz -= (worldPos.y/lightDir.y)*lightDir.xz;
worldPos.y = 0;
worldPos = mul(_Ground2World,worldPos);
worldPos = mul(unity_WorldToObject,worldPos);
o.pos = UnityObjectToClipPos(worldPos);
o.Value = 1-worldPos.z/14.0;
return o;
}
這個方案也有弊端,在效果上也有個小問題,就是過度旋轉地面plane之後,影子會出現一些問題,還有就是目前寫的隻有Directional Light的效果,在lightDir的計算上可以加入其他光源的判定。。
有合适的人,請看博文的人給推薦推薦?